cc2530下载程序

 

 外部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
}

你可能感兴趣的:(嵌入式开发)