Zigbee系列 学习笔记三(初始化程序解析)
1 int main( void ) 2 { 3 // Turn off interrupts 4 osal_int_disable( INTS_ALL ); 5 6 // Initialization for board related stuff such as LEDs 7 HAL_BOARD_INIT(); 8 9 // Make sure supply voltage is high enough to run 10 zmain_vdd_check(); 11 12 // Initialize board I/O 13 InitBoard( OB_COLD ); 14 15 // Initialze HAL drivers 16 HalDriverInit(); 17 18 // Initialize NV System 19 osal_nv_init( NULL ); 20 21 // Initialize the MAC 22 ZMacInit(); 23 24 // Determine the extended address 25 zmain_ext_addr(); 26 27 #if defined ZCL_KEY_ESTABLISH 28 // Initialize the Certicom certificate information. 29 zmain_cert_init(); 30 #endif 31 32 // Initialize basic NV items 33 zgInit(); 34 35 #ifndef NONWK 36 // Since the AF isn't a task, call it's initialization routine 37 afInit(); 38 #endif 39 40 // Initialize the operating system 41 osal_init_system(); 42 43 // Allow interrupts 44 osal_int_enable( INTS_ALL ); 45 46 // Final board initialization 47 InitBoard( OB_READY ); 48 49 // Display information about this device 50 zmain_dev_info(); 51 52 /* Display the device info on the LCD */ 53 #ifdef LCD_SUPPORTED 54 zmain_lcd_init(); 55 #endif 56 57 #ifdef WDT_IN_PM1 58 /* If WDT is used, this is a good place to enable it. */ 59 WatchDogEnable( WDTIMX ); 60 #endif 61 62 osal_start_system(); // No Return from here 63 64 return 0; // Shouldn't get here. 65 } // main()
HAL_BOARD_INIT()关于LED灯的板级初始化
1 #define HAL_BOARD_INIT() \ 2 { \ 3 uint16 i; \ 4 \ 5 SLEEPCMD &= ~OSC_PD; /* turn on 16MHz RC and 32MHz XOSC */ \ 6 while (!(SLEEPSTA & XOSC_STB)); /* wait for 32MHz XOSC stable */ \ 7 asm("NOP"); /* chip bug workaround */ \ 8 for (i=0; i<504; i++) asm("NOP"); /* Require 63us delay for all revs */ \ 9 CLKCONCMD = (CLKCONCMD_32MHZ | OSC_32KHZ); /* Select 32MHz XOSC and the source for 32K clock */ \ 10 while (CLKCONSTA != (CLKCONCMD_32MHZ | OSC_32KHZ)); /* Wait for the change to be effective */ \ 11 SLEEPCMD |= OSC_PD; /* turn off 16MHz RC */ \ 12 \ 13 /* Turn on cache prefetch mode */ \ 14 PREFETCH_ENABLE(); \ 15 \ 16 HAL_TURN_OFF_LED1(); \ 17 LED1_DDR |= LED1_BV; \ 18 HAL_TURN_OFF_LED2(); \ 19 LED2_DDR |= LED2_BV; \ 20 HAL_TURN_OFF_LED3(); \ 21 LED3_DDR |= LED3_BV; \ 22 \ 23 /* configure tristates */ \ 24 P0INP |= PUSH2_BV; \ 25 }
程序解读:16~21行代码,定义了三个LED灯的IO口,分别为P1_0、P1_1、P1_4。第24行代码,定义P0_0为三态
HalDriverInit()初始化硬件层各驱动
1 void HalDriverInit (void) 2 { 3 /* TIMER */ 4 #if (defined HAL_TIMER) && (HAL_TIMER == TRUE) 5 #error "The hal timer driver module is removed." 6 #endif 7 8 /* ADC */ 9 #if (defined HAL_ADC) && (HAL_ADC == TRUE) 10 HalAdcInit(); 11 #endif 12 13 /* DMA */ 14 #if (defined HAL_DMA) && (HAL_DMA == TRUE) 15 // Must be called before the init call to any module that uses DMA. 16 HalDmaInit(); 17 #endif 18 19 /* AES */ 20 #if (defined HAL_AES) && (HAL_AES == TRUE) 21 HalAesInit(); 22 #endif 23 24 /* LCD */ 25 #if (defined HAL_LCD) && (HAL_LCD == TRUE) 26 HalLcdInit(); 27 #endif 28 29 /* LED */ 30 #if (defined HAL_LED) && (HAL_LED == TRUE) 31 HalLedInit(); 32 #endif 33 34 /* UART */ 35 #if (defined HAL_UART) && (HAL_UART == TRUE) 36 HalUARTInit(); 37 #endif 38 39 /* KEY */ 40 #if (defined HAL_KEY) && (HAL_KEY == TRUE) 41 HalKeyInit(); 42 #endif 43 44 /* SPI */ 45 #if (defined HAL_SPI) && (HAL_SPI == TRUE) 46 HalSpiInit(); 47 #endif 48 49 /* HID */ 50 #if (defined HAL_HID) && (HAL_HID == TRUE) 51 usbHidInit(); 52 #endif 53 }
程序解析:以上程序分别进行了,定时器,ADC,UART等接口初始化
1 /* ------------------------------------------------------------------------------------------------ 2 * Driver Configuration 3 * ------------------------------------------------------------------------------------------------ 4 */ 5 6 /* Set to TRUE enable H/W TIMER usage, FALSE disable it */ 7 #ifndef HAL_TIMER 8 #define HAL_TIMER FALSE 9 #endif 10 11 /* Set to TRUE enable ADC usage, FALSE disable it */ 12 #ifndef HAL_ADC 13 #define HAL_ADC TRUE 14 #endif 15 16 /* Set to TRUE enable DMA usage, FALSE disable it */ 17 #ifndef HAL_DMA 18 #define HAL_DMA TRUE 19 #endif 20 21 /* Set to TRUE enable Flash access, FALSE disable it */ 22 #ifndef HAL_FLASH 23 #define HAL_FLASH TRUE 24 #endif 25 26 /* Set to TRUE enable AES usage, FALSE disable it */ 27 #ifndef HAL_AES 28 #define HAL_AES TRUE 29 #endif 30 31 #ifndef HAL_AES_DMA 32 #define HAL_AES_DMA TRUE 33 #endif 34 35 /* Set to TRUE enable LCD usage, FALSE disable it */ 36 #ifndef HAL_LCD 37 #define HAL_LCD TRUE 38 #endif 39 40 /* Set to TRUE enable LED usage, FALSE disable it */ 41 #ifndef HAL_LED 42 #define HAL_LED TRUE 43 #endif 44 #if (!defined BLINK_LEDS) && (HAL_LED == TRUE) 45 #define BLINK_LEDS 46 #endif 47 48 /* Set to TRUE enable KEY usage, FALSE disable it */ 49 #ifndef HAL_KEY 50 #define HAL_KEY TRUE 51 #endif 52 53 /* Set to TRUE enable UART usage, FALSE disable it */ 54 #ifndef HAL_UART 55 #if (defined ZAPP_P1) || (defined ZAPP_P2) || (defined ZTOOL_P1) || (defined ZTOOL_P2) 56 #define HAL_UART TRUE 57 #else 58 #define HAL_UART FALSE 59 #endif 60 #endif 61 62 #if HAL_UART 63 #ifndef HAL_UART_DMA 64 #if HAL_DMA 65 #if (defined ZAPP_P2) || (defined ZTOOL_P2) 66 #define HAL_UART_DMA 2 67 #else 68 #define HAL_UART_DMA 1 69 #endif 70 #else 71 #define HAL_UART_DMA 0 72 #endif 73 #endif 74 75 #ifndef HAL_UART_ISR 76 #if HAL_UART_DMA // Default preference for DMA over ISR. 77 #define HAL_UART_ISR 0 78 #elif (defined ZAPP_P2) || (defined ZTOOL_P2) 79 #define HAL_UART_ISR 2 80 #else 81 #define HAL_UART_ISR 1 82 #endif 83 #endif 84 85 #if (HAL_UART_DMA && (HAL_UART_DMA == HAL_UART_ISR)) 86 #error HAL_UART_DMA & HAL_UART_ISR must be different. 87 #endif 88 89 // Used to set P2 priority - USART0 over USART1 if both are defined. 90 #if ((HAL_UART_DMA == 1) || (HAL_UART_ISR == 1)) 91 #define HAL_UART_PRIPO 0x00 92 #else 93 #define HAL_UART_PRIPO 0x40 94 #endif 95 96 #else 97 #define HAL_UART_DMA 0 98 #define HAL_UART_ISR 0 99 #endif 100 101 /* USB is not used for CC2530 configuration */ 102 #define HAL_UART_USB 0 103 #endif 104 /******************************************************************************************************* 105 */
以上代码在hal_board_cfg.h中,定义了相应硬件接口。在HalDriverInit()函数中可以看到对应的硬件初始化。
针对ADC初始化:
1 void HalAdcInit (void)
2 {
3 #if (HAL_ADC == TRUE)
4 adcRef = HAL_ADC_REF_VOLT;
5 #endif
6 }
定义了ADC的参考电压源。
针对UART的初始化:
1 void HalUARTInit(void) 2 { 3 #if HAL_UART_DMA 4 HalUARTInitDMA(); 5 #endif 6 #if HAL_UART_ISR 7 HalUARTInitISR(); 8 #endif 9 #if HAL_UART_USB 10 HalUARTInitUSB(); 11 #endif 12 }
有三种初始化方式,可以通过hal_board_cfg.h文件中的定义进行选择初始化。
按键初始化:
1 void HalKeyInit( void ) 2 { 3 /* Initialize previous key to 0 */ 4 halKeySavedKeys = 0; 5 6 HAL_KEY_SW_6_SEL &= ~(HAL_KEY_SW_6_BIT); /* Set pin function to GPIO */ 7 HAL_KEY_SW_6_DIR &= ~(HAL_KEY_SW_6_BIT); /* Set pin direction to Input */ 8 9 HAL_KEY_JOY_MOVE_SEL &= ~(HAL_KEY_JOY_MOVE_BIT); /* Set pin function to GPIO */ 10 HAL_KEY_JOY_MOVE_DIR &= ~(HAL_KEY_JOY_MOVE_BIT); /* Set pin direction to Input */ 11 12 13 /* Initialize callback function */ 14 pHalKeyProcessFunction = NULL; 15 16 /* Start with key is not configured */ 17 HalKeyConfigured = FALSE; 18 }
初始化中定义了P0_1和P2_0为按键控制接口
关于DMA的配置过程:
1 /*用于配置DMA的结构体
2 -------------------------------------------------------*/
3 #pragma bitfields=reversed
4 typedef struct
5 {
6 unsigned char SRCADDRH; //源地址高8位
7 unsigned char SRCADDRL; //源地址低8位
8 unsigned char DESTADDRH; //目的地址高8位
9 unsigned char DESTADDRL; //目的地址低8位
10 unsigned char VLEN :3; //长度域模式选择
11 unsigned char LENH :5; //传输长度高字节
12 unsigned char LENL :8; //传输长度低字节
13 unsigned char WORDSIZE :1; //字节(byte)或字(word)传输
14 unsigned char TMODE :2; //传输模式选择
15 unsigned char TRIG :5; //触发事件选择
16 unsigned char SRCINC :2; //源地址增量:-1/0/1/2
17 unsigned char DESTINC :2; //目的地址增量:-1/0/1/2
18 unsigned char IRQMASK :1; //中断屏蔽
19 unsigned char M8 :1; //7或8bit传输长度,仅在字节传输模式下适用
20 unsigned char PRIORITY :2; //优先级
21 }DMA_CFG;
使用DMA的基本流程是:配置DMA → 启用配置 → 启动DMA传输 → 等待DMA传输完毕。下面分别介绍:
(1)配置DMA:首先必须配置DMA,但DMA的配置比较特殊:不是直接对某些SFR赋值,而是在外部定义一个结构体,对其赋值,然后再将此结构体的首地址的高8位赋给 DMA0CFGH,将其低8位赋给DMA0CFGL。
关于上面源码中对配置结构体的定义,需做两点说明:
1)位域
在定义此结构体时,用到了很多冒号(:),后面还跟着一个数字,这种语法叫“位域”:
位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
2)抽象出常用函数
细心的读者会发现,在对结构体赋值时,经常会涉及到将一个16位unsigned int 类型值分别赋予两个8位的unsigned char类型值,处理方法如下:
dmaConfig.SRCADDRL=(unsigned char)((unsignedint)&sourceString);
对于这类经常会用到的函数,我们不妨抽象出来作为一个通用函数,如下:
do{
destH=(unsigned char)((unsigned int)word >> 8);
destL=(unsigned char)((unsigned int)word);
}while(0)
以后每当你需要进行类似的分割操作时,直接调用即可,如下所示:
(2)启用配置:首先将结构体的首地址 &dmaConfig 的高/低8位分别赋给SFR DMA0CFGH 和DMA0CFGL(其中的0表示对通道0配置,CC2530包含5个DMA通道,此处使用通道0)。然对DMAARM.0 赋值1,启用通道0的配置,使通道0处于工作模式。
(3)开启DMA传输:对 DMAREQ.0 赋值1,启动通道0的DMA传输。
(4)等待DMA传输完毕:通道0的DMA传输完毕后,就会触发中断,通道0的中断标志 DMAIRQ.0会被自动置1。然后对两个字符串的每一个字符进行比较,将校验结果发送至PC。