/************************************************************************/
// CC2530 Programmer Example (using CC2530)
//
// This example uses: P0[0] as Debug Data (DD)
// P0[1] as Debug Clock (DC)
// P0[7] as RESET_N
//
// P0[7:1] are always output. P0[0] changes direction. P0[6:2] are 0.
//
// This example writes the following repetitive patten to the flash:
// "We make RF easy! We make RF easy! ..."
//
// In this example only 16 KB is written to the flash, stating from
// address 0x0000.
//
// Note that the primary focus of this example is to demonstration the
// flash programming algorithm. Thus, the code is not optimized for speed.
//
// Maximum speed is obtained when program_flash() returns 1. This can be
// achieved by writing more efficient write_debug_byte() and
// read_debug_byte() functions and making sure get_next_flash_byte()
// is quick. Compiler optimization should be set to maximum speed.
//
// DUP is used as an abbreviation for Device Under Programming.
//
/************************************************************************/
#include "../inc/ioCC2530.h"
#include "flash_image.h"
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
// 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
// Buffers
#define ADDR_BUF0 0x0000 // 1K
#define ADDR_BUF1 0x0400 // 1K
#define ADDR_DMA_DESC 0x0800 // 32 bytes
// DMA Channels
#define CH_DBG_TO_BUF0 0x02
#define CH_DBG_TO_BUF1 0x04
#define CH_BUF0_TO_FLASH 0x08
#define CH_BUF1_TO_FLASH 0x10
#define PROG_BLOCK_SIZE 1024
#define LOBYTE(w) ((uint8)(w))
#define HIBYTE(w) ((uint8)(((uint16)(w) >> 8) & 0xFF))
/*! \note This macro converts an XREG register declaration to an XDATA integer address */
#define XREG_TO_INT(a) ((uint16)(&(a)))
const uint8 dma_desc[32] = {
// Debug Interface -> Buffer 0 (Channel 1)
HIBYTE(XREG_TO_INT(DBGDATA)), // src[15:8]
LOBYTE(XREG_TO_INT(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
// Debug Interface -> Buffer 1 (Channel 2)
HIBYTE(XREG_TO_INT(DBGDATA)), // src[15:8]
LOBYTE(XREG_TO_INT(DBGDATA)), // src[7:0]
HIBYTE(ADDR_BUF1), // dest[15:8]
LOBYTE(ADDR_BUF1), // dest[7:0]
HIBYTE(PROG_BLOCK_SIZE),
LOBYTE(PROG_BLOCK_SIZE),
31, // trigger DBG_BW
0x11, // increment destination
// Buffer 0 -> Flash controller (Channel 3)
HIBYTE(ADDR_BUF0), // src[15:8]
LOBYTE(ADDR_BUF0), // src[7:0]
HIBYTE(XREG_TO_INT(FWDATA)), // dest[15:8]
LOBYTE(XREG_TO_INT(FWDATA)), // dest[7:0]
HIBYTE(PROG_BLOCK_SIZE),
LOBYTE(PROG_BLOCK_SIZE),
18, // trigger FLASH
0x42, // increment source
// Buffer 1 -> Flash controller (Channel 4)
HIBYTE(ADDR_BUF1), // src[15:8]
LOBYTE(ADDR_BUF1), // src[7:0]
HIBYTE(XREG_TO_INT(FWDATA)), // dest[15:8]
LOBYTE(XREG_TO_INT(FWDATA)), // dest[7:0]
HIBYTE(PROG_BLOCK_SIZE),
LOBYTE(PROG_BLOCK_SIZE),
18, // trigger FLASH
0x42 // increment source
};
uint16 flash_ptr = 0;
/*!
* \brief Initialize flash image pointer to start position
*/
void init_flash_ptr(void) {
flash_ptr = 0;
}
/*!
* \brief Gets the next flash image byte from the buffer
* \return Next flash image byte
*/
inline uint8 get_next_flash_byte(void) {
return flash_image[flash_ptr++];
}
/*!
* \brief Puts the DUP into debug mode
*/
void debug_init(void) {
volatile uint8 i;
// send two pulses on DC while keeping reset_n low
P0DIR = 0xFF; // all output's
P0 = 0x00;
for (i = 0; i < 10; i++);
P0 = 0x02;
P0 = 0x00;
P0 = 0x02;
P0 = 0x00;
for (i = 0; i < 10; i++);
P0 = 0x80; // release reset
}
/*!
* \brief Writes a byte on the debug interface. Sets the direction of port 0 at the end.
* P0_0 must be output when this function is called.
* \param data Byte to write
* \param dir Direction of all pins on port 0 that is to be written at the end.
*/
inline void write_debug_byte(uint8 data, uint8 dir) {
uint8 i;
for (i = 0; i < 8; i++) {
P0 = (data & 0x80) ? 0x83 : 0x82;
data <<= 1;
P0 &= ~0x02; // set clock low
}
P0DIR = dir;
}
/*!
* \brief Reads a byte from the debug interface. Requires P0_0 to be input when
* function is called.
* \return Byte read
*/
inline uint8 read_debug_byte(void) {
uint8 i;
uint8 data;
for (i = 0; i < 8; i++) {
P0 = 0x82; // clock out data
data <<= 1;
data |= P0 & 0x01;
P0 = 0x80;
}
return data;
}
/*!
* \brief Issues a command on the debug interface. Only commands that return one
* output byte are supported.
* \param cmd Command byte
* \param input_bytes Pointer to the array of input bytes
* \param num_input_bytes The number of input bytes
* \return Data returned by command
*/
uint8 debug_command(uint8 cmd, uint8 *input_bytes, uint16 num_input_bytes) {
uint16 i;
uint8 output = 0;
uint8 dir;
// change direction to input if no input bytes
dir = (num_input_bytes == 0) ? 0xFE : 0xFF;
write_debug_byte(cmd, dir);
for (i = 0; i < num_input_bytes; i++) {
// change direction to input for the last byte
dir = (i == num_input_bytes-1) ? 0xFE : 0xFF;
write_debug_byte(input_bytes[i], dir);
}
// Wait for data to be ready
while (P0 & 0x01) {
read_debug_byte();
}
output = read_debug_byte();
P0DIR = 0xFF;
return output;
}
/*!
* \brief Performs the BURST_WRITE command on the debug interface
*/
void burst_write() {
uint16 i;
write_debug_byte(CMD_BURST_WRITE | HIBYTE(PROG_BLOCK_SIZE), 0xFF);
write_debug_byte(LOBYTE(PROG_BLOCK_SIZE), 0xFF);
for (i = 0; i < PROG_BLOCK_SIZE-1; i++) {
write_debug_byte(get_next_flash_byte(), 0xFF);
}
write_debug_byte(get_next_flash_byte(), 0xFE); // change dir. to input
while (P0 & 0x01) {
read_debug_byte();
}
read_debug_byte(); // ignore output
P0DIR = 0xFF;
}
/*!
* \brief Issues a CHIP_ERASE command on the debug interface and waits for it
* to complete.
*/
void chip_erase(void) {
debug_command(CMD_CHIP_ERASE, 0, 0);
while (debug_command(CMD_READ_STATUS, 0, 0) & 0x80);
}
/*!
* \brief Writes a block of data to the XDATA region in the DUP
* \param address XDATA start address
* \param values Pointer to the array of bytes to write
* \param num_bytes Number of bytes to write
*/
void write_xdata_memory_block(uint16 address, const uint8 *values, uint16 num_bytes) {
uint8 instr[3];
uint16 i;
// MOV DPTR, address
instr[0] = 0x90;
instr[1] = HIBYTE(address);
instr[2] = LOBYTE(address);
debug_command(CMD_DEBUG_INSTR | 3, instr, 3);
for (i = 0; i < num_bytes; i++) {
// MOV A, values[i]
instr[0] = 0x74;
instr[1] = values[i];
debug_command(CMD_DEBUG_INSTR | 2, instr, 2);
// MOV @DPTR, A
instr[0] = 0xF0;
debug_command(CMD_DEBUG_INSTR | 1, instr, 1);
// INC DPTR
instr[
- 1
- 2
- 3
- 4
前往页