Chinaunix首页 | 论坛 | 博客
  • 博客访问: 488464
  • 博文数量: 93
  • 博客积分: 1431
  • 博客等级: 上尉
  • 技术积分: 1006
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-18 10:30
文章分类

全部博文(93)

文章存档

2011年(20)

2010年(2)

2009年(71)

我的朋友

分类: 嵌入式

2011-07-20 11:37:15

ZSTACK HAL 底层 驱动修改笔记

针对CC2530 zigbee 创新套件 CITE-T-VC

                                                               谷良增

                                                               2010-8-26

文档修改记录:

2010-9-28

针对 CITE-T-ZA套件,添加SPI 移植部分

 

 

目录:

LED

KEY 轮询方式

KEY 中断方式

串口

SPI

 

 

一:LED       

硬件连接情况:   P0_1-----LED1;   P0_2-----LED2;  P0_3-----LED3;  P2_0-----LED4

相关文件 hal_board_cfg.h

文件位置:C:\Texas Instruments\ZStack-CC2530-2.3.0-1.4.0\Components\hal\target\CC2530EB

工程中的位置:HAL—Target—CC2530EB—Config--- hal_board_cfg.h

注意:hal_led.c 文件只是实现了ZSTACK  HAL_LED 接口函数,此文件不用修改。

 

1.       修改LED 接口 ,例子:LED1---P1_0

/* 1 - Green */

#define LED1_BV           BV(0)

#define LED1_SBIT         P1_0

#define LED1_DDR          P1DIR

#define LED1_POLARITY     ACTIVE_HIGH

 

2添加一个 LED ,如添加 LED4  (P2_0)

#define LED4_BV           BV(0)

#define LED4_SBIT         P2_0

#define LED4_DDR          P2DIR

#define LED4_POLARITY     ACTIVE_LOW

 

ZSTACK  HAL_LED 接口函数

  #define HAL_TURN_OFF_LED4()       st( LED4_SBIT = LED4_POLARITY (0); )

 

  #define HAL_TURN_ON_LED4()        st( LED4_SBIT = LED4_POLARITY (1); )

 

  #define HAL_TOGGLE_LED4()         st( if (LED4_SBIT) { LED4_SBIT = 0; } else { LED4_SBIT = 1;} )

 

  #define HAL_STATE_LED4()           (LED4_POLARITY (LED4_SBIT))

 

3由于有:

/* Set to TRUE enable LED usage, FALSE disable it */

#ifndef HAL_LED

#define HAL_LED TRUE

#endif

#if (!defined BLINK_LEDS) && (HAL_LED == TRUE)

#define BLINK_LEDS

#endif

所以工程OPTIONS 编译选项不需要再去设置HAL_LEDBLINK_LEDS

 

4. 在该文件 HAL_BOARD_INIT()宏定义中 ,初始化 P0_2,P0_3 不管用。因为在ZSTACK 中这两脚 被用作UART TX,RX,所以 LED 控制端口P0_1,P0_2,P0_3,P2_0的初始化工作放在 main()函数中 int_led();

void init_led(void)

{

        //ADD BY GU FOR init LED

      P0SEL &=0xF1;

      P0DIR |= 0x0E;                  //设置P0.1P0.2P0.3为输出 

      P2SEL &=~(0x1);

      P2DIR |=0x01;

      P2_0=1;

}

5. hal_board_cfg  中有 按键初始化部分,不方便删除(直接删除会引起编译出错),所以 将其该到了 P0_6,P0_7 上。眼下P0_6,P0_7 悬空估计 不会有其他副作用。

//changed by gu

 

/* S1 */

#define PUSH1_BV          BV(7)

#define PUSH1_SBIT        P0_7

 

/* Joystick Center Press */

#define PUSH2_BV          BV(6)

#define PUSH2_SBIT        P0_6

#define PUSH2_POLARITY    ACTIVE_HIGH

 

二:按键的处理之 KEY  轮询方式

硬件连接情况:   P0_0-----SW2;

相关文件 hal_key.c

文件位置:C:\Texas Instruments\ZStack-CC2530-2.3.0-1.4.0\Components\hal\target\CC2530EB

工程中的位置:HAL—Target—CC2530EB—Drivers--- hal_led.c

1..修改按键端口 定义(P0_0

/* SW_2 is at P0.0 */

#define HAL_KEY_SW_2_PORT   P0

#define HAL_KEY_SW_2_BIT    BV(0)

#define HAL_KEY_SW_2_SEL    P0SEL

#define HAL_KEY_SW_2_DIR    P0DIR

 

/* SW_2 interrupts */

#define HAL_KEY_SW_2_IEN      IEN1  /* CPU interrupt mask register */

#define HAL_KEY_SW_2_IENBIT   BV(5) /* Mask bit for all of Port_0 */

#define HAL_KEY_SW_2_ICTL     P0IEN /* Port Interrupt Control register */

#define HAL_KEY_SW_2_ICTLBIT  BV(0) /* P0IEN - P0.0 enable/disable bit */

#define HAL_KEY_SW_2_PXIFG    P0IFG /* Interrupt flag at source */按键端口 初始

化:

 

2.void HalKeyInit( void ) 函数中

 

  添加:

//add by gu

  HAL_KEY_SW_2_SEL &= ~(HAL_KEY_SW_2_BIT);    /* Set pin function to GPIO */

  HAL_KEY_SW_2_DIR &= ~(HAL_KEY_SW_2_BIT);    /* Set pin direction to Input */

3. HalKeyConfig函数中 屏蔽中断

    //add by gu

      HAL_KEY_SW_2_ICTL &= ~(HAL_KEY_SW_2_ICTLBIT); /* don't generate interrupt */

HAL_KEY_SW_2_IEN &= ~(HAL_KEY_SW_2_IENBIT);   /* Clear interrupt enable bit */

我们这里不采用中断方式,使用轮询方式。延伸阅读:

ZMain.c 文件 main.c 函数中

       调用了  // Initialize board I/O

  InitBoard( OB_COLD );

 

OnBoard.c 定义了  InitBoard()函数

最后有初始化 KEY 的操作

 

   /* Initialize Key stuff */

OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;

    采用了非中断模式

    HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);

4         HalKeyRead 函数中添加

    if (!P0_0)

  {

    keys |= HAL_KEY_SW_2;

  }

 

5         HalKeyPoll  函数中添加

 

    if (!P0_0)

  {

    keys |= HAL_KEY_SW_2; (此处最关键,决定了ZSTACK 认为这是 SW 几)

  }

至此   hal_key.c 修改完毕

6         KEY 相应函数,在你的应用文件例如GenericApp.c   GenericApp_HandleKeys函数里if ( keys & HAL_KEY_SW_2 ) 添加按键响应代码

6.KEY 的修改 其实挺简单,(1)初始化 按键输入端口,可在 HalKeyInit 函数中,也可在main函数中,(2HalKeyPoll  函数中if (!P0_0)

  {

    keys |= HAL_KEY_SW_2; (此处最关键,决定了ZSTACK 认为这是 SW 几)

  }

报告OS 按键 事件的发生

7. 现在 按键 是电平触发 且无防抖,有时会出现 按下一次 会响应多次。可以考虑使用按键中断处理机制

 

  按键的处理之 KEY  中断方式

硬件连接情况:   P0_0-----SW2;

OnBoard.c

1. 定义了  InitBoard()函数

最后有初始化 KEY 的操作

   /* Initialize Key stuff */

OnboardKeyIntEnable = HAL_KEY_INTERRUPT_ENABLE;

    采用了中断模式

    HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);

 

han_key.c 中的 设置

2.预定义 相关信息,详情参见2530数据手册

/* SW_2 is at P0.0 */

#define HAL_KEY_SW_2_PORT   P0

#define HAL_KEY_SW_2_BIT    BV(0)

#define HAL_KEY_SW_2_SEL    P0SEL

#define HAL_KEY_SW_2_DIR    P0DIR

 

/* edge interrupt */

#define HAL_KEY_SW_2_EDGEBIT  BV(0)

#define HAL_KEY_SW_2_EDGE     HAL_KEY_FALLING_EDGE

 

/* SW_2 interrupts */

#define HAL_KEY_SW_2_IEN      IEN1  /* CPU interrupt mask register */

#define HAL_KEY_SW_2_IENBIT   BV(5) /* Mask bit for all of Port_0 */

#define HAL_KEY_SW_2_ICTL     P0IEN /* Port Interrupt Control register */

#define HAL_KEY_SW_2_ICTLBIT  BV(0) /* P0IEN - P0.0 enable/disable bit */

#define HAL_KEY_SW_2_PXIFG    P0IFG /* Interrupt flag at source */

3.  HalKeyInit 函数 初始化P0_0 输入脚

  HAL_KEY_SW_2_SEL &= ~(HAL_KEY_SW_2_BIT);    /* Set pin function to GPIO */

  HAL_KEY_SW_2_DIR &= ~(HAL_KEY_SW_2_BIT);    /* Set pin direction to Input */

 

4. HalKeyConfig 函数 设置 中断 打开,及中断方式 下降沿中断

 

    PICTL &= ~(HAL_KEY_SW_2_EDGEBIT);    /* Clear the edge bit */

    /* For falling edge, the bit must be set. */

PICTL |= HAL_KEY_SW_2_EDGEBIT;

 

/* Interrupt configuration:

     * - Enable interrupt generation at the port

     * - Enable CPU interrupt

     * - Clear any pending interrupt

     */

    HAL_KEY_SW_2_ICTL |= HAL_KEY_SW_2_ICTLBIT;

    HAL_KEY_SW_2_IEN |= HAL_KEY_SW_2_IENBIT;

    HAL_KEY_SW_2_PXIFG = ~(HAL_KEY_SW_2_BIT);

   

osal_stop_timerEx( Hal_TaskID, HAL_KEY_EVENT); 开启 按键事件 定时器

 

5. 中断函数

HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )

{

  if (HAL_KEY_SW_2_PXIFG & HAL_KEY_SW_2_BIT)

  {

    halProcessKeyInterrupt();

  }

  /*

    Clear the CPU interrupt flag for Port_0

    PxIFG has to be cleared before PxIF

  */

  HAL_KEY_SW_2_PXIFG = 0;

  HAL_KEY_CPU_PORT_0_IF = 0;

}

6. 中断处理函数

void halProcessKeyInterrupt (void)

{

  bool valid=FALSE;

    if (HAL_KEY_SW_2_PXIFG & HAL_KEY_SW_2_BIT)  /* Interrupt Flag has been set */

  {

    HAL_KEY_SW_2_PXIFG = ~(HAL_KEY_SW_2_BIT); /* Clear Interrupt Flag */

    valid = TRUE;

  }

 

  if (valid)

  {

    osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);

  }

}

 向系统 报告 按键事件

7         用户层的按键处理,在你的应用文件例如GenericApp.c   GenericApp_HandleKeys函数里if ( keys & HAL_KEY_SW_2 ) 添加按键响应代码

 

8. 以下分析摘自《zigbee 技术实践教程基于CC2430/31的无线传感器网络解决方案》一书258

   任务事件处理函数接收到KEY_CHANGE 消息的途径:

(1)       按键被按下,HAL 层检测到按键状态变化(通过H/W 中断或 轮询)

(2)       HAL 对应的OSAL 任务检测 到按键的状态变化,触发OSAL 按键变化的回调函数

(3)       OSAL 按键变化回调函数发送一OSAL 的系统事件消息给已经注册过的任务

   OS内部 更为详细的 调用过程详见《zigbee 技术实践教程基于CC2430/31的无线传感器网络解决方案》一书345--347

 

UART

1.首先 确保hal_board_cfg.h定义了

#define HAL_UART TRUE

 

//add by gu

#define HAL_UART_DMA  0

#define HAL_UART_ISR  1

定义为 串口中断模式,如果为 DMA 模式的话,HalUARTWrite发送数据时 会丢掉 第二个字符

 

2.       串口初始化

void init_uart(byte task_id)

{

 // uint8 *buf="abcdefghigklmn123456789";

  halUARTCfg_t uartConfig;

 

  uartConfig.configured           = TRUE;              //   don't care.

  uartConfig.baudRate             = HAL_UART_BR_115200;  // CC2430 only allow 38.4k or 115.2k

  uartConfig.flowControl          = HAL_UART_FLOW_OFF;  // Turn off flow control to fit most serial ports' setting

  uartConfig.flowControlThreshold = SERIAL_PORT_THRESH; 

  uartConfig.rx.maxBufSize        = SERIAL_PORT_RX_MAX; 

  uartConfig.tx.maxBufSize        = SERIAL_PORT_TX_MAX; 

  uartConfig.idleTimeout          = SERIAL_PORT_IDLE;   // don't care. 

  uartConfig.intEnable            = TRUE;              //  don't care.

  uartConfig.callBackFunc         = uartrxCB;

 

  HalUARTOpen (HAL_UART_PORT_0, &uartConfig);

 

 // Set an event to start the application 

 // osal_set_event(task_id, ZB_ENTRY_EVENT);

 

 // HalUARTWrite ( HAL_UART_PORT_0, buf, strlen(buf) );

 

}

各参数详解详见HAL Driver API.pdfUART 一章

3.       串口接收

/*********************************************************************

 * 串口接收回调函数

 * 用于串口回显

 */

void uartrxCB(uint8 port,uint8 event)

{     

       uint8  *buf;

       uint8 len; 

       if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)))

       {

            buf = osal_mem_alloc( SERIAL_PORT_RX_CNT );

             if ( buf!=NULL ) 

             {   

               len = HalUARTRead( HAL_UART_PORT_0, buf, SERIAL_PORT_RX_CNT ); 

               if(len>0)

               {

                sensor_SendSensorMessage(buf);

                 } 

                 osal_mem_free( buf );  

       //     osal_set_event( sensor_TaskID, SERIAL_PORT_MSG_RCV_EVT );

// 触发 OS 提供的 串口事件

       }

       }

}

     注意:如果没有 if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)))

这一句判断,串口接收会出错。

 

4.       串口发送:

  HalUARTWrite ( HAL_UART_PORT_0, buf, len ); //FOR TEST

5.       此处并未使用 OS 提供的 串口事件,实现了 串口数据回显的功能。

事实上可以用OS 提供的 串口事件实现串口功能,具体实现可参考 TI 提供的透明串口实验SerailApp

 OS 提供的 串口事件:

 

HAL_UART_RX_FULL

Rx Buffer is full

 

 

HAL_UART_RX_ABOUT_FULL

Rx Buffer is at maxRxBufSize - flowControlThreshold

HAL_UART_RX_TIMEOUT

Rx is idle for idleTimout time

HAL_UART_TX_FULL

Tx Buffer is full

HAL_UART_TX_EMPTY

Tx Buffer is free to write more data

 

摘自:《HAL Driver API.pdfUART 一章

 

方式二:关于 串口事件

也可以自定义事件,在串口接收 回调函数里 触发该事件,在该事件里 进行串口接收处理

具体 事件 处理方式 如下:

1. 定义串口接收事件编号  #define UART_RX_CB_EVT                0x0002 

事件编号的定义:必须用左移一位的方式 实现 例如0x0001,0x0002,0x0004,0x0008

 

2. 在串口 回调函数中 ,接收数据存到全局数组中, 触发 串口接收事件

/* 触发 串口接收事件 UART_RX_CB_EVT

 */

void uartrxCB(uint8 port,uint8 event)

{ 

      if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)))

       {   

        HalUARTRead( HAL_UART_PORT_0, pcmd, CMD_LENGTH );

        osal_set_event( GenericApp_TaskID, UART_RX_CB_EVT);

       }

}

3. 串口接收事件 中对 串口接收数据 进行再处理

if ( events & UART_RX_CB_EVT )

  {

  //串口接收事件  串口回显命令(TEST),再通过 无线方式发送给 子节点

     HalUARTWrite ( HAL_UART_PORT_0, pcmd , CMD_LENGTH ); // for test

    

     GenericApp_SendCmdMessage(pcmd,CMD_LENGTH);

    // return unprocessed events

    return (events ^ UART_RX_CB_EVT);

  }

 

串口接收事件 在应用层 事件处理函数GenericApp_ProcessEvent()中,该函数由系统负责调用。GenericApp_ProcessEvent 为用户任务在 OSAL_GenericApp.c 文件

// The order in this table must be identical to the task initialization calls below in osalInitTask.

const pTaskEventHandlerFn tasksArr[] 中添加

 

 

五:

                                                SPI   ZSTACK 移植记录

 

1.       HAL ---- Target---------CC2530EB----Drivers 文件夹 添加 Hal_spi.c Hal_spi.h 文件

D:\Texas Instruments\ZStack-CC2530-2.3.0-1.4.0\Components\hal\target\CC2530EB 文件夹下

2.       HAL------Common  文件夹 hal_drivers.c

添加 SPI 初始化和 SPI 中断轮询    SPI 初始化:

void HalDriverInit (void)

{

。。。。。。。。。。。

  /* SPI */

#if (defined HAL_SPI) && (HAL_SPI == TRUE)

  HalSpiInit();

#endif

。。。。。。。。。。。。。

}

Main.c 中会调用 HalSpiInit()

 

SPI 中断轮询:

void Hal_ProcessPoll ()

{

。。。。。。。。。。。。。。。。。

  /* SPI Poll */

//add by gu

#if (defined HAL_SPI) && (HAL_SPI == TRUE)

 // HalSpiPoll();

   HalSpiIntPoll();

#endif

。。。。。。。。。。。。。。。。。。。

}

 

Main.c 中会调用 osal_start_system ,其中不断 会调用 HalSpiIntPoll()

 

其中HalSpiInit();  HalSpiIntPoll(); 具体定义在Hal_spi.c中定义实现

(其实 原来就有 只需要我们实现一下)

 

3.       对于 SPI 发送使用 轮询机制:

直接调用  发送函数发送即可

 

4.       对于 SPI 接收 采用 中断方式; 中断处理 函数  HAL_ISR_FUNCTION( halSpiIsr, URX1_VECTOR )Hal_spi.c中定义

当接收完 一包数据 并校验通过后,触发 接收事件  

osal_set_event( sensor_TaskID, SPI_POLL_EVT );

 

在应用层 sensor.c

UINT16 sensor_ProcessEvent( byte task_id, UINT16 events )

SPI接收事件SPI_POLL_EVT中会根据  数据类型 处理这一包数据:

    if ( events & SPI_POLL_EVT )

  {            

        switch (  SpiRecBuf[1])

        {

        case SENSOR_EVENT:

 

。。。。。。。。。。

    // return unprocessed events

return (events ^ SPI_POLL_EVT);

}

5.       对于 按键的处理:

当在SPI 接收的按键数据包中分析出按键值后,向当前 任务发送按键 消息,触发按键 处理

 

向当前 任务发送按键 消息:

        case KEY_EVENT:

 

                   switch (SpiRecBuf[3])

                  {

                   case KEY_1:

            

                   OnBoard_SendKeys(HAL_KEY_SW_1,0);

                 

                      break;

                    case KEY_2:

           

                    OnBoard_SendKeys(HAL_KEY_SW_2,0);

 

                      break;

……………………………………..

OnBoard_SendKeys 函数在 OnBoard.c 中定义

最后调用了     osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );

 

触发按键 处理:

 

UINT16 sensor_ProcessEvent( byte task_id, UINT16 events )

{

 系统事件

  if ( events & SYS_EVENT_MSG )

  {

    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( sensor_TaskID );

    while ( MSGpkt )

    {

      switch ( MSGpkt->hdr.event )

      {

   ………………………………….

         

        case KEY_CHANGE:

          sensor_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );

          break;

………………………………………

          }

 

用户的按键处理接口:

 

void sensor_HandleKeys( byte shift, byte keys )

{

  if ( shift )

  {

    if ( keys & HAL_KEY_SW_1 )

    {

    }

    if ( keys & HAL_KEY_SW_2 )

    {

    }

  }

  else

  {

    if ( keys & HAL_KEY_SW_1 )

{

 

用户的按键处理接口:

}

。。。。。。。。。。。。。。。。。

 

阅读(11369) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~