ZigBee_CC2530_08H_HAL层分析
扫描二维码
随时随地手机看文章
Zigbee的HAL层提供了开发板所有硬件设备(例如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()执行闪烁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目录下包含了某个设备类型下的硬件驱动文件、硬件开发板上的配置文件、MCU信息和数据类型。
CC2530EB中的字符EB是TI公司的Zstack在某个硬件上实现的版本号。例如:BB是电池版(Battery Board);DB是开发版(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文件中可以定义开发版的硬件资源。以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的状态,取值可以是:HAL_LED_MODE_ON、HAL_LED_MODE_OFF和HAL_LED_MODE_TOGGLE。
HalLedBlink()函数控制LED灯闪烁:
参数numBlinks:闪烁次数。
参数percent:LED亮和灭的所用时间占空比。
参数period:LED闪烁一个周期所需要的时间,以毫秒为单位。