外部mcu通过调试接口对CC2530进行编程,基本的功能函数如下:
//--cc2530 Debug commands---
#define CMD_CHIP_ERASE 0x10
#define CMD_WR_CONFIG 0x18
#define CMD_RD_CONFIG 0x20
#define CMD_READ_STATUS 0x30
#define CMD_RESUME 0x48
#define CMD_DEBUG_INSTR 0x50
#define CMD_BURST_WRITE 0x80
#define CMD_GET_CHIP_ID 0x68
//---------------------------
#define LOBYTE(w) ((unsigned char)(w))
#define HIBYTE(w) ((unsigned char)(((unsigned short)(w) >> 8) & 0xFF))
#define FCTL 0x6270
#define FADDRL 0x6271
#define FADDRH 0x6272
#define FWDATA 0x6273
#define DBGDATA 0x6260 //DMA register
#define X_DMAARM 0x70D6 // DMA Channel Arm
#define X_DMAREQ 0x70D7
#define X_DMA1CFGL 0x70D2 // DMA Channel 1-4 Configuration Address Low Byte
#define X_DMA1CFGH 0x70D3 // DMA Channel 1-4 Configuration Address High Byte
// Buffers
#define ADDR_BUF0 0x0000 // 1K,存放来自调试接口的数据,长度为1K,0x0000--0x03FF
#define ADDR_DMA_DESC 0x0400 // 从0x0400地址开始存放16字节的数据
#define PROG_BLOCK_SIZE 0xFD
// DMA Channels
#define CH_DBG_TO_BUF0 0x02 //使用通道1
#define CH_BUF0_TO_FLASH 0x04 //使用通道2
//--mcu使用的下载接口引脚,可以根据具体的mcu修改----
sbit DcPin = PADBUF^5;
sbit DdPin = PADBUF^3;
sbit ResetPin = PADBUF^1;
sbit DcPinDir = PADCON1^5;
sbit DdPinDir = PADCON1^3;
sbit ResetPinDir = PADCON1^1;
//-------------------------------------------------------------------------
void Delayus(unsigned short us)
{
while(us--)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
}
/*********************************************************************************
* Writes a byte on the debug interface. Sets the direction of port 0 at the end.
* DdPin must be output when this function is called.
* param:
num---Byte to write
dir---Direction of all pins on port 0 that is to be written at the end.
*********************************************************************************/
void cc2530_Write_Debug_Byte(unsigned char num, unsigned char dir)
{
unsigned char i;
for (i=0; i<8; i++)
{
DdPin = (num&0x80) ? 1 : 0;
DcPin = 1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
num <<= 1;
DcPin = 0; //在时钟的下降沿把数据输出
}
DdPinDir = dir;
}
/*****************************************************
* Reads a byte from the debug interface.
* Requires DdPin to be input when function is called.
* return:
Byte read
*****************************************************/
unsigned char cc2530_Read_Debug_Byte(void)
{
unsigned char i,num;
for (i = 0; i < 8; i++)
{
DcPin = 1; // clock out data
num <<= 1;
num |= DdPin;
DcPin = 0;
}
return num;
}
/**********************************************************************************************************************
* brief Issues a command on the debug interface. Only commands that return one
* param:
cmd---Command byte
input_bytes---Pointer to the array of input bytes
num_input_bytes---The number of input bytes
* return Data:
returned by command
**********************************************************************************************************************/
unsigned char cc2530_Write_Debug_Command(unsigned char cmd, unsigned char *input_bytes, unsigned short num_input_bytes)
{
unsigned short i;
unsigned char output = 0;
unsigned char dir;
dir = (num_input_bytes == 0) ? 0 : 1;//如果没有输入字节,把方向改为输入
cc2530_Write_Debug_Byte(cmd, dir);
for(i = 0; i < num_input_bytes; i++)
{
dir = (i == num_input_bytes-1) ? 0 : 1;//在最后一个字节把方向改为输入
cc2530_Write_Debug_Byte(input_bytes[i], dir);
}
while( DdPin&1 ) //等待cc2530的引脚方向改变完成,拉低此引脚,说明cc2530已经准备好输出数据
{
cc2530_Read_Debug_Byte();
}
output = cc2530_Read_Debug_Byte();
//重新配置SDI引脚为输出
DdPinDir = 1;
return output;
}
/*************************************
* 读取cc2530的ID值
* 参数:
* buf:输出数据缓存,2个字节
*************************************/
void cc2530_Get_Id(unsigned char *buf)
{
cc2530_Write_Debug_Byte(CMD_GET_CHIP_ID,0);
while( DdPin&1 ) //等待cc2530的引脚方向改变完成,拉低此引脚,说明cc2530已经准备好输出数据
{
cc2530_Read_Debug_Byte();
}
buf[0] = cc2530_Read_Debug_Byte();
buf[1] = cc2530_Read_Debug_Byte();
}
/*************************************************************************
* write a byte to the XDATA in the DUP
* param:
* address----XDATA address
values---the bytes to write
*************************************************************************/
void cc2530_Write_Xdata_Memory(unsigned short address, unsigned char value)
{
unsigned char instr[3];
instr[0] = 0x90;
instr[1] = HIBYTE(address);
instr[2] = LOBYTE(address);
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 3, instr, 3); //MOV DPTR,#data16
instr[0] = 0x74; //把立即数送到寄存器A
instr[1] = value;
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 2, instr, 2); //MOV A,#data
instr[0] = 0xF0; //把数据从寄存器A写入外部RAM
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 1, instr, 1); //MOVX @DPTR,A
}
/**********************************************************************************************************
* Writes a block of data to the XDATA region in the DUP
* param:
address---XDATA start address
values---Pointer to the array of bytes to write
num_bytes---Number of bytes to write
***********************************************************************************************************/
void cc2530_Write_Xdata_Memory_Block(unsigned short address, const unsigned char *values, unsigned short num_bytes)
{
unsigned char instr[3];
unsigned short i;
instr[0] = 0x90;
instr[1] = HIBYTE(address);
instr[2] = LOBYTE(address);
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 3, instr, 3); //MOV DPTR,#data16
for (i = 0; i < num_bytes; i++)
{
instr[0] = 0x74; //把立即数送到寄存器A
instr[1] = values[i];
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 2, instr, 2); //MOV A,#data
instr[0] = 0xF0; //把数据从寄存器A写入外部RAM
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 1, instr, 1); //MOVX @DPTR,A
instr[0] = 0xA3; //增加数据指针
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 1, instr, 1);//INC DPTR
}
}
/***********************************************************
* Read a byte from a specific address in XDATA in the DUP
* param:
* address----XDATA address
* return Value
* read from XDATA
***********************************************************/
unsigned char cc2530_Read_Xdata_Memory(unsigned short address)
{
unsigned char instr[3];
instr[0] = 0x90;
instr[1] = HIBYTE(address);
instr[2] = LOBYTE(address);
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 3, instr, 3); //MOV DPTR,#data16
instr[0] = 0xE0; //把外部RAM(16为地址)的值写入寄存器A
return cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 1, instr, 1); //MOVX A,@DPTR
}
/************************************************************************************************************
* 读取cc2530 xdata区的数据
* 参数:
* address:xdata区地址
* pOutBuf:输出数据缓存
* num_bytes:要读取的数据长度
* 返回值:
* 无
***********************************************************************************************************/
void cc2530_Read_Xdata_Memory_Block(unsigned short address, unsigned char *pOutBuf, unsigned short num_bytes)
{
unsigned char instr[3];
unsigned short i;
instr[0] = 0x90;
instr[1] = HIBYTE(address);
instr[2] = LOBYTE(address);
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 3, instr, 3); //MOV DPTR,#data16
for( i=0; i
instr[0] = 0xE0; //把外部RAM(16为地址)的值写入寄存器A
pOutBuf[i] = cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 1, instr, 1); //MOVX A,@DPTR
instr[0] = 0xA3; //增加数据指针
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 1, instr, 1); //INC DPTR
}
}
/****************************************************
* 写cc2530的sfr寄存器
* 参数:
* address:寄存器地址
* value:要写入的值
* 返回值:
* 无
***************************************************/
void cc2530_Write_Sfr(unsigned char address,unsigned char value)
{
unsigned char instr[3];
instr[0] = 0x75;//移动一个立即数到直接地址,此处即把bank值写入寄存器address
instr[1] = address;
instr[2] = value;
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 3, instr, 3); //MOV direct,#data
}
/****************************************************
* 读取cc2530的sfr寄存器
* 参数:
* address:寄存器地址
* 返回值:
* 寄存器中的值
***************************************************/
unsigned char cc2530_Read_Sfr(unsigned char address)
{
unsigned char instr[2];
instr[0] = 0xE5;//把寄存器0x9F中的值写入寄存器A
instr[1] = address;
return cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 2, instr, 2);//MOV A,direct
}
/********************************************************************
* 依次把数据写入到调试接口
* 参数:
* buf:要写入的数据缓存
* num_bytes:要写入的数据字节数
********************************************************************/
void cc2530_Burst_Write(unsigned char *buf, unsigned char num_bytes)
{
unsigned char i;
cc2530_Write_Debug_Byte( CMD_BURST_WRITE, 1 );
cc2530_Write_Debug_Byte( num_bytes, 1 );
for(i=0; i
cc2530_Write_Debug_Byte(buf[i], 1); //
}
cc2530_Write_Debug_Byte(buf[i], 0); // change dir. to input
while( DdPin&1 )
{
cc2530_Read_Debug_Byte();
}
cc2530_Read_Debug_Byte(); // ignore output
//重新配置SDI引脚为输出
DdPinDir = 1;
}
/******************************************************************************************************************
* 往cc2530的flash中写入数据
* 参数:
* lAddr:flash中的线性地址
* buf:写入数据缓存
* num_bytes:要写入的字节数
* 返回值:
* 无
*******************************************************************************************************************/
void cc2530_Write_Code_Memory(unsigned long lAddr, unsigned char *buf, unsigned char num_bytes)
{
unsigned short sAddr;
unsigned char dma_desc[16] =
{
// Debug Interface -> Buffer 0 (Channel 1)
HIBYTE(DBGDATA), // src[15:8]
LOBYTE(DBGDATA), // src[7:0]
HIBYTE(ADDR_BUF0), // dest[15:8]
LOBYTE(ADDR_BUF0), // dest[7:0]
HIBYTE(PROG_BLOCK_SIZE),
LOBYTE(PROG_BLOCK_SIZE),
31, // trigger DBG_BW
0x11, // increment destination
// Buffer 0 -> Flash controller (Channel 2)
HIBYTE(ADDR_BUF0), // src[15:8]
LOBYTE(ADDR_BUF0), // src[7:0]
HIBYTE(FWDATA), // dest[15:8]
LOBYTE(FWDATA), // dest[7:0]
HIBYTE(PROG_BLOCK_SIZE),
LOBYTE(PROG_BLOCK_SIZE),
18, // trigger FLASH
0x42, // increment source
};//此处只配置了通道1与通道2,通道1把调试接口输入的数据搬移到ADD_BUF0开始的xdata空间,通道2把ADD_BUF0处的数据写入flash
sAddr = (unsigned short)(lAddr>>2);//由于写入flash时是字(4字节)寻址的,用16位地址(64K)访问256k的空间,256K=64*4
dma_desc[5] = dma_desc[13] = num_bytes;
// Write the 2 DMA descriptors
cc2530_Write_Xdata_Memory_Block(ADDR_DMA_DESC, dma_desc, 16);// 16 bytes,从0x0400地址开始存放dma_desc数组中的数据
// Set the pointer to the DMA descriptors
cc2530_Write_Xdata_Memory(X_DMA1CFGH, HIBYTE(ADDR_DMA_DESC));
cc2530_Write_Xdata_Memory(X_DMA1CFGL, LOBYTE(ADDR_DMA_DESC));
cc2530_Write_Xdata_Memory(FADDRH, HIBYTE(sAddr));//设置flash的地址
cc2530_Write_Xdata_Memory(FADDRL, LOBYTE(sAddr));
cc2530_Write_Xdata_Memory(X_DMAARM, CH_DBG_TO_BUF0);//把数据从调试接口搬移到xdata区
cc2530_Burst_Write(buf,num_bytes);
// wait for write to finish
while(cc2530_Read_Xdata_Memory(FCTL) & 0x80);
// start programming current buffer
cc2530_Write_Xdata_Memory(X_DMAARM, CH_BUF0_TO_FLASH);
cc2530_Write_Xdata_Memory(FCTL, 0x06); //把数据从xdata区写入flash中
// Programming last buffer in progress, wait until done
while(cc2530_Read_Xdata_Memory(FCTL) & 0x80);
}
/******************************************************************************************************************
* 读取cc2530flash中的代码
* 参数:
* sAddr:bank区中的地址值,其中bank0:0x0000--0x7FFF, bank1-bankn:0x8000--0xFFFF
* bank:对应的bank值
* pOutBuf:输出数据缓存
* num_bytes:要读取的字节数
* 返回值:
* 无
* 对应flash中的线性地址(linear address)与bank值和bank中的地址对应的计算公式如下:
* 如果sAddr<0x8000, linear address = sAddr;
* 如果sAddr>=0x8000,linear address = (sAddr&0x7fff) + bank*0x8000
*******************************************************************************************************************/
void cc2530_Read_Code_Memory(unsigned short sAddr, unsigned char bank, unsigned char *pOutBuf, unsigned char num_bytes)
{
unsigned char i;
unsigned char instr[3];
instr[0] = 0x75;//移动一个立即数到直接地址,此处即把bank值写入寄存器0x9F
instr[1] = 0x9F;
instr[2] = bank;
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 3, instr, 3);
instr[0] = 0x90;
instr[1] = HIBYTE(sAddr);
instr[2] = LOBYTE(sAddr);
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 3, instr, 3);
for( i=0; i
instr[0] = 0xE4; //清寄存器A
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 1, instr, 1);
instr[0] = 0x93; //把数据从外部RAM写入寄存器A
pOutBuf[i] = cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 1, instr, 1);
instr[0] = 0xA3; //增加数据指针
cc2530_Write_Debug_Command(CMD_DEBUG_INSTR | 1, instr, 1);
}
}
//配置下载主控器的编程引脚
void mcu_Init_Debug_Io()
{
unsigned char debug_config;
unsigned short X_CLKCONCMD = 0x70C6;
unsigned short X_CLKCONSTA = 0x709E;
//引脚方向性选择,初始化配置调试接口为输出
DdPinDir = 1;//0->输入,1->输出
DcPinDir = 1;
ResetPinDir = 1;
ResetPin = 1; //初始化复位引脚为高电平
DcPin = 0; //初始化时钟电平为低电平
DdPin = 0;
Delayus(10); //大约延时24us
//在复位线拉低的情况下,输出两个clk
ResetPin = 0;
Delayus(10);
DcPin = 1;
_nop_();
_nop_();
_nop_();
DcPin = 0;
_nop_();
_nop_();
_nop_();
DcPin = 1;
_nop_();
_nop_();
_nop_();
DcPin = 0;
_nop_();
_nop_();
_nop_();
Delayus(10);
ResetPin = 1;
debug_config = 0x22;
cc2530_Write_Debug_Command(CMD_WR_CONFIG, &debug_config, 1);
// Switch to 32 Mhz and wait for it to be stable. This is recommended if
// 32 MHz crystal is available during programming. If 32 MHz crystal is
// not available, comment out these two lines.
cc2530_Write_Xdata_Memory(X_CLKCONCMD, 0x80);
while(cc2530_Read_Xdata_Memory(X_CLKCONSTA) != 0x80);
}
//主控器通过调试接口擦除cc2530
void mcu_Erase_Cc2530()
{
cc2530_Write_Debug_Command(CMD_CHIP_ERASE, 0, 0);
while(cc2530_Write_Debug_Command(CMD_READ_STATUS, 0, 0) & 0x80);//查询擦除是否完成,擦除完成后最高位清0
}