? Zigbee的HAL層提供了開發(fā)板所有硬件設備(例如LED、LCD、KEY、UART等)的驅動函數和接口。HAL文件夾為硬件平臺的抽象層,包含common、include和target三個文件夾。
1 Common文件夾? common文件夾下包含有hal_assert.c和hal_drivers.c兩個文件。其中hal_assert.c是聲明文件,用于調試,hal_drivers.c是驅動文件
1.1 hal_assert.c? 在hal_assert.c文件中包含兩個重要的函數:halAssertHandler()和halAssertHazardLights()。
1.1.1 halAssertHandle()函數? halAssertHandler()函數為硬件系統檢測函數。如果定義了ASSERT_RESET宏,系統將調用HAL_SYSTEM_RESET復位,否則將調用halAssertHazardLights()執(zhí)行閃爍LED命令。
void halAssertHandler(void)
{
/* execute code that handles asserts */
//如果定義了ASSERT_RESET宏定義
#ifdef ASSERT_RESET
//系統復位
HAL_SYSTEM_RESET();
#elif !defined ASSERT_WHILE
//當檢測到錯誤,LED燈閃爍命令函數
halAssertHazardLights();
#else
while(1);
#endif
}
1.1.2 halAssertHazardLights()函數
? halAssertHazardLights()函數控制LED燈閃爍,根據不同的硬件平臺定義的LED的個數來決定閃爍的LED的不同。其控制LED燈閃爍代碼如下:
//如果硬件平臺定義的LED燈的個數是1
#if (HAL_NUM_LEDS >= 1)
//LED1閃爍
HAL_TOGGLE_LED1();
#if (HAL_NUM_LEDS >= 2)
HAL_TOGGLE_LED2();
#if (HAL_NUM_LEDS >= 3)
HAL_TOGGLE_LED3();
#if (HAL_NUM_LEDS >= 4)
HAL_TOGGLE_LED4();
#endif
#endif
#endif
#endif
其完整定義可自行查看。
1.2 hal_drivers.c
? hal_drivers.c文件中包含了與硬件相關的初始化和事件處理函數。此文件中有4個比較重要的函數:硬件初始化函數Hal_Init()、硬件驅動初始化函數HalDriverInit()、硬件事件處理函數Hal_ProcessEvent()和詢檢函數Hal_ProcessPoll()。
1.2.1Hal_Init()函數? Hal_Init()函數是硬件初始化函數,其功能是通過“注冊任務ID號”以實現在OSAL層注冊,從而允許硬件驅動的消息和事件由OSAL處理。其函數內容為:
void Hal_Init( uint8 task_id )
{
/* Register task ID */
Hal_TaskID = task_id;
#ifdef CC2591_COMPRESSION_WORKAROUND
osal_start_reload_timer( Hal_TaskID, PERIOD_RSSI_RESET_EVT, PERIOD_RSSI_RESET_TIMEOUT );
#endif
}
1.2.2 HalDriverInit()函數
? HalDriverInit()函數被main()函數調用,用于初始化與硬件設備有關的驅動。HalDriverInit()函數的具體功能如下:
void HalDriverInit (void)
{
/* TIMER */
//如果定義了定時器則初始化定時器
#if (defined HAL_TIMER) && (HAL_TIMER == TRUE)
//在Zstack-CC2530-2.5.1a版本中移除了定時器的初始化,但不影響Zstack的運行。
#error "The hal timer driver module is removed."
#endif
/* ADC */
//如果定義了ADC,初始化ADC
#if (defined HAL_ADC) && (HAL_ADC == TRUE)
HalAdcInit();
#endif
/* DMA */
//如果定義了DMA,初始化DMA
#if (defined HAL_DMA) && (HAL_DMA == TRUE)
// Must be called before the init call to any module that uses DMA.
HalDmaInit();
#endif
/* AES */
//如果定義了AES,初始化AES
#if (defined HAL_AES) && (HAL_AES == TRUE)
HalAesInit();
#endif
/* LCD */
//如果定義了LCD,初始化LCD
#if (defined HAL_LCD) && (HAL_LCD == TRUE)
HalLcdInit();
#endif
/* LED */
//如果定義了LED,初始化LED
#if (defined HAL_LED) && (HAL_LED == TRUE)
HalLedInit();
#endif
/* UART */
//如果定義了UART,初始化UART
#if (defined HAL_UART) && (HAL_UART == TRUE)
HalUARTInit();
#endif
/* KEY */
//如果定義了按鍵,初始化KEY
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
HalKeyInit();
#endif
/* SPI */
//如果定義了SPI,初始化SPI
#if (defined HAL_SPI) && (HAL_SPI == TRUE)
HalSpiInit();
#endif
/* HID */
//如果定義了USB,初始化USB,只限CC2531
#if (defined HAL_HID) && (HAL_HID == TRUE)
usbHidInit();
#endif
}
1.2.3 Hal_ProcessEvent()函數
? Hal_ProcessEvent()函數在APP層中的任務事件處理中被調用,用于對相應的硬件事件作出處理,具體包括系統消息事件、LED閃爍事件、按鍵處理事件和睡眠模式等。
uint16 Hal_ProcessEvent( uint8 task_id, uint16 events )
{
uint8 *msgPtr;
(void)task_id; // Intentionally unreferenced parameter
//系統消息事件
if ( events & SYS_EVENT_MSG )
{
msgPtr = osal_msg_receive(Hal_TaskID);
while (msgPtr)
{
/* Do something here - for now, just deallocate the msg and move on */
/* De-allocate */
osal_msg_deallocate( msgPtr );
/* Next */
msgPtr = osal_msg_receive( Hal_TaskID );
}
return events ^ SYS_EVENT_MSG;
}
//LED閃爍事件
if ( events & HAL_LED_BLINK_EVENT )
{
#if (defined (BLINK_LEDS)) && (HAL_LED == TRUE)
HalLedUpdate();
#endif /* BLINK_LEDS && HAL_LED */
return events ^ HAL_LED_BLINK_EVENT;
}
//按鍵處理事件
if (events & HAL_KEY_EVENT)
{
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
/* Check for keys */
HalKeyPoll();
/* if interrupt disabled, do next polling */
if (!Hal_KeyIntEnable)
{
osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
}
#endif // HAL_KEY
return events ^ HAL_KEY_EVENT;
}
//睡眠模式
#ifdef POWER_SAVING
if ( events & HAL_SLEEP_TIMER_EVENT )
{
halRestoreSleepLevel();
return events ^ HAL_SLEEP_TIMER_EVENT;
}
#endif
#ifdef CC2591_COMPRESSION_WORKAROUND
if ( events & PERIOD_RSSI_RESET_EVT )
{
macRxResetRssi();
return (events ^ PERIOD_RSSI_RESET_EVT);
}
#endif
/* Nothing interested, discard the message */
return 0;
}
1.2.4 Hal_ProcessPoll()函數
? Hal_ProcessPoll()函數在main()函數中被osal_start_system()調用,用來對可能產生的硬件事件進行詢檢。函數原型為:
void Hal_ProcessPoll ()
{
/* Timer Poll */
//定時器詢檢
#if (defined HAL_TIMER) && (HAL_TIMER == TRUE)
#error "The hal timer driver module is removed."
#endif
/* UART Poll */
//UART詢檢,即串口詢檢
#if (defined HAL_UART) && (HAL_UART == TRUE)
HalUARTPoll();
#endif
/* SPI Poll */
#if (defined HAL_SPI) && (HAL_SPI == TRUE)
HalSpiPoll();
#endif
/* HID poll */
//USB詢檢(僅限CC2530)
#if (defined HAL_HID) && (HAL_HID == TRUE)
usbHidProcessEvents();
#endif
//如果定義了休眠模式
#if defined( POWER_SAVING )
/* Allow sleep before the next OSAL event loop */
//允許在下一個事件到來之前進入休眠模式
ALLOW_SLEEP_MODE();
#endif
}
? 硬件驅動初始化函數HalDriverInit()和硬件事件處理函數Hal_ProcessEvent()是Zigbee協議棧固有的,一般不需要作出較大范圍的修改,只需直接使用即可。 2. Include文件夾
3. Target文件夾
? Target目錄下包含了某個設備類型下的硬件驅動文件、硬件開發(fā)板上的配置文件、MCU信息和數據類型。
? CC2530EB中的字符EB是TI公司的Zstack在某個硬件上實現的版本號。例如:BB是電池版(Battery Board);DB是開發(fā)版(Development Board),EB是評估版(Evaluate Board)
? 在CC2530EB文件夾下包含了三個子文件夾,分別是Config、Derive、Includes
3.1 Config文件夾? Config文件夾中包含了hal_board_cfg.h,在hal_board_cfg.h中定義了硬件CC2530硬件資源的配置,比如GPIO、DMA、ADC等。
? 在hal_board_cfg.h文件中可以定義開發(fā)版的硬件資源。以LED為例,TI官方的CC2530EB版本定義了兩個LED:LED1和LED2,其在hal_board_cfg.h中定義如下:
/* 1 - Green */
//有關LED1的宏定義
#define LED1_BV BV(0)
#define LED1_SBIT P1_0
#define LED1_DDR P1DIR
#define LED1_POLARITY ACTIVE_HIGH
//如果定義了HAL_BOARD_CC2530EB_REC17,則定了LED2和LED3
#if defined (HAL_BOARD_CC2530EB_REV17)
/* 2 - Red */
//有關LED2的宏定義
#define LED2_BV BV(1)
#define LED2_SBIT P1_1
#define LED2_DDR P1DIR
#define LED2_POLARITY ACTIVE_HIGH
/* 3 - Yellow */
//有關LED3的宏定義
#define LED3_BV BV(4)
#define LED3_SBIT P1_4
#define LED3_DDR P1DIR
#define LED3_POLARITY ACTIVE_HIGH
#endif
? LED宏定義完成之后,設置LED的打開和關閉,其代碼在hal_board_cfg.h文件中,代碼如下:
#if defined (HAL_BOARD_CC2530EB_REV17) && !defined (HAL_PA_LNA) && !defined (HAL_PA_LNA_CC2590)
#define HAL_TURN_OFF_LED1() st( LED1_SBIT = LED1_POLARITY (0); )
#define HAL_TURN_OFF_LED2() st( LED2_SBIT = LED2_POLARITY (0); )
#define HAL_TURN_OFF_LED3() st( LED3_SBIT = LED3_POLARITY (0); )
#define HAL_TURN_OFF_LED4() HAL_TURN_OFF_LED1()
#define HAL_TURN_ON_LED1() st( LED1_SBIT = LED1_POLARITY (1); )
#define HAL_TURN_ON_LED2() st( LED2_SBIT = LED2_POLARITY (1); )
#define HAL_TURN_ON_LED3() st( LED3_SBIT = LED3_POLARITY (1); )
#define HAL_TURN_ON_LED4() HAL_TURN_ON_LED1()
#define HAL_TOGGLE_LED1() st( if (LED1_SBIT) { LED1_SBIT = 0; } else { LED1_SBIT = 1;} )
#define HAL_TOGGLE_LED2() st( if (LED2_SBIT) { LED2_SBIT = 0; } else { LED2_SBIT = 1;} )
#define HAL_TOGGLE_LED3() st( if (LED3_SBIT) { LED3_SBIT = 0; } else { LED3_SBIT = 1;} )
#define HAL_TOGGLE_LED4() HAL_TOGGLE_LED1()
#define HAL_STATE_LED1() (LED1_POLARITY (LED1_SBIT))
#define HAL_STATE_LED2() (LED2_POLARITY (LED2_SBIT))
#define HAL_STATE_LED3() (LED3_POLARITY (LED3_SBIT))
#define HAL_STATE_LED4() HAL_STATE_LED1()
3.2 Derivers文件夾
? 以最常用的LED為例,在hal_led.c文件中提供了兩個封裝好的函數,在應用層可以直接調用,以控制LED。這兩個函數是:
uint8 HalLedSet (uint8 leds, uint8 mode);
void HalLedBlink (uint8 leds, uint8 numBlinks, uint8 percent, uint16 period);
3.2.1 HalLedSet()函數
? HalLedSet()函數控制LED的亮滅:
3.2.2 HalLedBlink()函數參數leds,指LED的名稱,取值可以是:HAL_LED_1、HAL_LED_2、HAL_LED_3和HAL_LED_4;
參數mode,指LED的狀態(tài),取值可以是:HAL_LED_MODE_ON、HAL_LED_MODE_OFF和HAL_LED_MODE_TOGGLE。
? HalLedBlink()函數控制LED燈閃爍:
???????????? 參數numBlinks:閃爍次數。
???????????? 參數percent:LED亮和滅的所用時間占空比。
???????????? 參數period:LED閃爍一個周期所需要的時間,以毫秒為單位。