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。