概述
TI 的Z-Stack 提供两种解决方案,一种基于TI 2530芯片为核心的Zigbee解决方案,另一种为ZNP(Zigbee and Processor),即CC2530+MCU的解决方案,这是TI提供的两种不同的解决方案。
硬件配置
当前使用的ZNP方案为MT7620N+CC2530的方式,MT7620N与CC2530采用UART接口通讯。
管脚 CC2530
UART-RXD P0_2 Pin17
UART-TXD P0_3 Pin16
VCC x x
GND x x
ZNP工程设置(基于Z-Stack Home 1.2.2a.44539)
在Z-Stack协议栈中,TI已经已经实现了ZNP工程,工程目录位于
Z-Stack Home 1.2.2a.44539\Projects\zstack\ZNP\cc253x
打开工程选择CC2530-DEBUG进行相关的修改。
参考资料:
Z-Stack Home 1.2.2a.44539\Documents\API\Z-Stack ZNP Interface Specification.pdf 第2.3章节
里面描述了CC2530ZNP的硬件接口
Step1.使能CC2530串口支持
通过ZNP Interface Specification 2.3.1.1 中的硬件接口描述可以看到,CFG1接口为高电平时CC2530使能SPI接口,位低电平时CC2530使能UART接口。
CFG0控制CC2530是使用内置32k时钟还是外置时钟。
这个初始化配置位于void InitBoard( uint8 level )函数中。
void InitBoard( uint8 level )
{
if ( level == OB_COLD )
{
// IAR does not zero-out this byte below the XSTACK.
*(uint8 *)0x0 = 0;
// Interrupts off
osal_int_disable( INTS_ALL );
// Check for Brown-Out reset
ChkReset();
#if defined CC2531ZNP
znpCfg1 = ZNP_CFG1_UART;
#elif defined CC2530_MK
znpCfg1 = ZNP_CFG1_SPI;
znpCfg0 = ZNP_CFG0_32K_OSC;
#else
//znpCfg1 = P2_0;
//znpCfg0 = P1_2;
// Tri-state the 2 CFG inputs after being read (see hal_board_cfg_xxx.h for CFG0.)
//P1INP |= BV(2);
//P2INP |= BV(0);
znpCfg1 = ZNP_CFG1_UART; //使能UART功能
znpCfg0 = ZNP_CFG0_32K_XTAL;//使能外部32K时钟
#endif
}
else // !OB_COLD
{
/* Initialize Key stuff */
HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback);
}
}
Step2 关闭Uart流控
默认的情况下ZNP串口通信是使能流控,但是ZAP上面并没有使用流控,所以需要关闭ZNP中的流控功能。
流控主要是在串口初始化的时候配置。代码位于
znp_app.c:
static void npInit(void)
{
if (ZNP_CFG1_UART == znpCfg1)
{
halUARTCfg_t uartConfig;
uartConfig.configured = TRUE;
uartConfig.baudRate = ZNP_UART_BAUD;
#ifdef ZNP_ALT
uartConfig.flowControl = FALSE;
#else
uartConfig.flowControl = FALSE;//TRUE;//关闭流控
#endif
uartConfig.flowControlThreshold = HAL_UART_FLOW_THRESHOLD;
uartConfig.rx.maxBufSize = HAL_UART_RX_BUF_SIZE;
uartConfig.tx.maxBufSize = HAL_UART_TX_BUF_SIZE;
uartConfig.idleTimeout = HAL_UART_IDLE_TIMEOUT;
uartConfig.intEnable = TRUE;
uartConfig.callBackFunc = npUartCback;
HalUARTOpen(HAL_UART_PORT, &uartConfig);
MT_UartRegisterTaskID(znpTaskId);
}
else
{
/* npSpiInit() is called by hal_spi.c: HalSpiInit().*/
}
npInitNV();
#if defined (MT_ZDO_FUNC)
MT_ZdoInit();
#endif
MT_SysResetInd();
#if defined ZCL_KEY_ESTABLISH
#if defined TC_LINKKEY_JOIN
zcl_TaskID = znpTaskId;
#endif
#endif
#if LQI_ADJUST
ZMacLqiAdjustMode(LQI_ADJ_MODE1);
#endif
#if defined CC2531ZNP
(void)osal_pwrmgr_task_state(znpTaskId, PWRMGR_HOLD);
#endif
}
Step3 注意串口处理函数
串口通讯协议可以查看
Z-Stack Home 1.2.2a.44539\Documents\API\Z-Stack Monitor and Test API.pdf
在串口数据处理使用了void MT_UartProcessZToolData ( uint8 port, uint8 event )函数,该函数位于MT_UART.c文件下,有时在其他的工程中可能会修改该函数,来达到处理自己私有串口协议的目的。这样会造成在使用ZNP时无法通讯的问题,只需要还原到最初的串口处理方式就可以解决问题。
MT_UART.c:
void MT_UartProcessZToolData ( uint8 port, uint8 event )
{
uint8 ch;
uint8 bytesInRxBuffer;
(void)event; // Intentionally unreferenced parameter
while (Hal_UART_RxBufLen(port))
{
HalUARTRead (port, &ch, 1);
switch (state)
{
case SOP_STATE:
if (ch == MT_UART_SOF)
state = LEN_STATE;
break;
case LEN_STATE:
LEN_Token = ch;
tempDataLen = 0;
/* Allocate memory for the data */
pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) +
MT_RPC_FRAME_HDR_SZ + LEN_Token );
if (pMsg)
{
/* Fill up what we can */
pMsg->hdr.event = CMD_SERIAL_MSG;
pMsg->msg = (uint8*)(pMsg+1);
pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;
state = CMD_STATE1;
}
else
{
state = SOP_STATE;
return;
}
break;
case CMD_STATE1:
pMsg->msg[MT_RPC_POS_CMD0] = ch;
state = CMD_STATE2;
break;
case CMD_STATE2:
pMsg->msg[MT_RPC_POS_CMD1] = ch;
/* If there is no data, skip to FCS state */
if (LEN_Token)
{
state = DATA_STATE;
}
else
{
state = FCS_STATE;
}
break;
case DATA_STATE:
/* Fill in the buffer the first byte of the data */
pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen++] = ch;
/* Check number of bytes left in the Rx buffer */
bytesInRxBuffer = Hal_UART_RxBufLen(port);
/* If the remain of the data is there, read them all, otherwise, just read enough */
if (bytesInRxBuffer <= LEN_Token - tempDataLen)
{
HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], bytesInRxBuffer);
tempDataLen += bytesInRxBuffer;
}
else
{
HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], LEN_Token - tempDataLen);
tempDataLen += (LEN_Token - tempDataLen);
}
/* If number of bytes read is equal to data length, time to move on to FCS */
if ( tempDataLen == LEN_Token )
state = FCS_STATE;
break;
case FCS_STATE:
FSC_Token = ch;
/* Make sure it's correct */
if ((MT_UartCalcFCS ((uint8*)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ + LEN_Token) == FSC_Token))
{
osal_msg_send( App_TaskID, (byte *)pMsg );
}
else
{
/* deallocate the msg */
osal_msg_deallocate ( (uint8 *)pMsg );
}
/* Reset the state, send or discard the buffers at this point */
state = SOP_STATE;
break;
default:
break;
}
}
}
Step4 修改ZNP参数
在Z-Stack Monitor and Test API.pdf中有许多的功能,如果想添加这些功能可以在工程的Tools/znp.cfg中定义相关的功能宏。
Tools/znp.cfg:
#znp.cfg:
-DZNP_UART_BAUD=HAL_UART_BR_115200 //修改串口波特率
-DZIGBEEPRO
-DZIGBEE_FRAGMENTATION
-DINTER_PAN
-DOSAL_CLOCK
-DOSAL_SAPI=FALSE
-DSAPI_CB_FUNC=FALSE
Tools/f8wconfig.cfg:
在该配置中,可以修改信道等信息
编译测试
在修改完成后,进行编译并下载到CC2530中。
使用USB转串口,与CC2530的Uart0连接。然后使用Z-TOOLS工具进行测试。
测试结果:
下一步就是移植zigbee linux gateway 到mt7620N上面。MT7620N上面运行的是openwrt系统。