CCHL, a hardware ChipCon programmer following swra124, running on CC1110.

Follows (almost) same protocol as CCTL, so same client s/w runs on osx/linux/win
This commit is contained in:
Joby Taffey committed 2012-03-12 00:21:27 +00:00
1 parent ce3b5b77a7
commit 07ff76a515
10 files changed
+1785 -6

No files matched your search

+6 -2
View File
@@ -1,8 +1,12 @@
all:
make -C boot
make -C cctl
make -C cctl-prog
make -C cchl
make -C example_payload
clean:
make -C boot clean
make -C cctl clean
make -C cctl-prog clean
make -C cchl clean
make -C example_payload clean
+10
View File
@@ -4,6 +4,8 @@ CC Tiny Loader
CCTL is a serial bootloader for the Chipcon CC1110/CC1111 using only one 1KB page of flash.
It allows update of the the microcontroller firmware over its serial port.
Included is CCHL, ChipCon Hardware Loader, an application which runs on the CC111x and can program a slave device over the ChipCon debug interface (http://focus.ti.com/lit/ug/swra124/swra124.pdf)
The bootloader consists of two components, a piece of firmware that is flashed
onto the device and a utility for downloading code and manipulating the
flash memory. The client program, `cctl-prog` runs on Linux, OSX/Darwin and Windows.
@@ -138,6 +140,13 @@ The protocol is given in detail in http://focus.ti.com/lit/ug/swra124/swra124.pd
(CCTL is placed in the flash using this protocol, it is different to the serial protocol).
If you have access to one of the devices below, you can bootstrap out of it, by programming CCHL into a CC1110. CCHL allows the CC1110 to program virgin chips over the debug interface.
To reflash a slave device, connect P1_6 to DD, P1_5 to DC and P1_4 to RESET, load `cchl.hex` onto a CC1110 running CCTL and run `cctl-prog` using the `--passthrough` flag. Eg. to program the `cctl` bootloader into a device:
`./cctl-prog -p -d /dev/ttyUSB0 -f cctl.hex`
Official hardware programmer
* TI's CC-Debugger http://www.ti.com/tool/cc-debugger (Windows only)
@@ -152,6 +161,7 @@ Open source implementations of protcol
* Teensy (C) https://github.com/jkerdels/open_imme/tree/master/tools/teensy-prog
* Linux GPIO sysfs (C) https://github.com/ffainelli/cc2530prog
Building for Windows
--------------------
+45
View File
@@ -0,0 +1,45 @@
CC = sdcc
CFLAGS = --model-small --opt-code-speed
# NOTE: code-loc should be the same as the value specified for
# USER_CODE_BASE in the bootloader!
LDFLAGS_FLASH = \
--out-fmt-ihx \
--code-loc 0x400 --code-size 0x8000 \
--xram-loc 0xf000 --xram-size 0x1000 \
--iram-size 0x100
ifdef DEBUG
CFLAGS += --debug
endif
SRC = main.c
ADB=$(SRC:.c=.adb)
ASM=$(SRC:.c=.asm)
LNK=$(SRC:.c=.lnk)
LST=$(SRC:.c=.lst)
REL=$(SRC:.c=.rel)
RST=$(SRC:.c=.rst)
SYM=$(SRC:.c=.sym)
PROGS=cchl.hex
PCDB=$(PROGS:.hex=.cdb)
PLNK=$(PROGS:.hex=.lnk)
PMAP=$(PROGS:.hex=.map)
PMEM=$(PROGS:.hex=.mem)
PAOM=$(PROGS:.hex=)
%.rel : %.c
$(CC) -c $(CFLAGS) -o$*.rel $<
all: $(PROGS)
cchl.hex: $(REL) Makefile
$(CC) $(LDFLAGS_FLASH) $(CFLAGS) -o cchl.hex $(REL)
clean:
rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
rm -f $(PROGS) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
File renamed without changes.
+416
View File
@@ -0,0 +1,416 @@
/*
* CCHL - ChipCon Hardware Loader
* A hardware programmer for the CC1110/CC1111 which runs on the CC1110/CC1111
* Joby Taffey (c) 2012 <jrt-cctl@hodgepig.org>
*
* Derived from:
* CC Bootloader
* Fergus Noble (c) 2011
*
* Open IMME https://github.com/jkerdels/open_imme
* Jochen kerdels
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <stdint.h>
#include <cc1110.h>
#include "cc1110-ext.h"
// Connect the target CC1110 up as follows
#define DD P1_6
#define DD_BIT BIT6
#define DC P1_5
#define DC_BIT BIT5
#define RST P1_4
#define RST_BIT BIT4
#define RXFIFO_ELEMENTS 2048
#define RXFIFO_SIZE (RXFIFO_ELEMENTS - 1)
static __xdata uint8_t rxfifo[RXFIFO_SIZE];
static uint8_t rxfifo_in;
static uint8_t rxfifo_out;
static const __code uint8_t * __at (0x0000) flashp;
__xdata uint8_t rambuf[1024];
static uint8_t page;
static const char banner[] = {'\r', '\n', 'C', 'C', 'H', 'L', '\r', '\n'};
#define BIT0 1
#define BIT1 2
#define BIT2 4
#define BIT3 8
#define BIT4 16
#define BIT5 32
#define BIT6 64
#define BIT7 128
#define ST_CHIP_ERASE_DONE 0x80
#define ST_PCON_IDLE 0x40
#define ST_CPU_HALTED 0x20
#define ST_POWER_MODE_0 0x10
#define ST_HALT_STATUS 0x08
#define ST_DEBUG_LOCKED 0x04
#define ST_OSCILLATOR_STABLE 0x02
#define ST_STACK_OVERFLOW 0x01
#define FLASHPAGE_SIZE 1024
#define FLASH_WORD_SIZE 2
#define WORDS_PER_FLASH_PAGE 512
#define nop() __asm nop __endasm;
void delay (unsigned char n)
{
unsigned char i = 0;
unsigned char j = 0;
n <<= 1;
while (--n != 0)
while (--i != 0)
while (--j != 0)
nop();
}
static void send_byte(uint8_t ch)
{
int8_t i;
P1DIR |= DD_BIT; // output
for (i = 7; i >= 0; i--)
{
if (ch & (1 << i))
DD = 1;
else
DD = 0;
DC = 1;
DC = 0;
}
}
static uint8_t recv_byte(void)
{
uint8_t ch = 0;
int8_t i;
P1DIR &= ~DD_BIT; // input
for (i = 7; i >= 0; i--)
{
DC = 1;
if (DD)
ch |= (1 << i);
DC = 0;
}
return ch;
}
static void dbg_init(void)
{
P1DIR |= RST_BIT;
P1DIR |= DC_BIT; // DC
P1DIR |= DD_BIT; // DD
DD = 0;
// send debug init sequence
RST = 0;
delay(1);
DC = 0;
delay(1);
DC = 1;
delay(1);
DC = 0;
delay(1);
DC = 1;
delay(1);
DC = 0;
delay(1);
RST = 1;
delay(1);
}
static uint8_t read_status(void)
{
send_byte(0x34);
return recv_byte();
}
static void dbg_mass_erase(void)
{
send_byte(0x14);
recv_byte();
while (!(read_status() & ST_CHIP_ERASE_DONE));
}
static uint8_t debug_instr_1(uint8_t in0)
{
send_byte(0x55);
send_byte(in0);
return recv_byte();
}
static uint8_t debug_instr_2(uint8_t in0, uint8_t in1)
{
send_byte(0x56);
send_byte(in0);
send_byte(in1);
return recv_byte();
}
static uint8_t debug_instr_3(uint8_t in0, uint8_t in1, uint8_t in2)
{
send_byte(0x57);
send_byte(in0);
send_byte(in1);
send_byte(in2);
return recv_byte();
}
static void write_xdata_memory(uint16_t address, uint16_t count, const __xdata uint8_t *buf)
{
int i;
debug_instr_3(0x90,address >> 8,address);
for (i = 0; i < count; ++i) {
debug_instr_2(0x74, buf[i]);
debug_instr_1(0xF0);
debug_instr_1(0xA3);
}
}
static void set_pc(uint16_t address)
{
debug_instr_3(0x02,address >> 8,address);
}
static void cpu_resume(void)
{
send_byte(0x4C);
recv_byte(); // ignore sent value
}
static void read_code_memory(uint16_t address,
uint8_t bank,
uint16_t count,
__xdata uint8_t *outputData)
{
int i;
if (address >= 0x8000)
address = (address & 0x7FFF) + (bank * 0x8000);
debug_instr_3(0x75,0xC7,(bank * 16) + 1);
debug_instr_3(0x90,address >> 8,address);
for (i = 0; i < count; ++i) {
debug_instr_1(0xE4);
outputData[i] = debug_instr_1(0x93);
debug_instr_1(0xA3);
}
}
static __xdata uint8_t updProc[] =
{
0x75, 0xAD, /*ADDRESS*/0x00,
0x75, 0xAC, 0x00,
0x75, 0xAB, 0x23, 0x00,
0x75, 0xAE, 0x01, // ------
0xE5, 0xAE, // erase code
0x20, 0xE7, 0xFB, // ------
0x90, 0xF0, 0x00,
0x7F, WORDS_PER_FLASH_PAGE >> 8,
0x7E, WORDS_PER_FLASH_PAGE & 0xFF,
0x75, 0xAE, 0x02,
0x7D, FLASH_WORD_SIZE,
0xE0,
0xA3,
0xF5, 0xAF,
0xDD, 0xFA,
0xE5, 0xAE,
0x20, 0xE6, 0xFB,
0xDE, 0xF1,
0xDF, 0xEF,
0xA5
};
static void write_flash_page(uint32_t address)
{
uint8_t updProcSize = sizeof(updProc);
updProc[2] = ((address >> 8) / FLASH_WORD_SIZE) & 0x7E;
write_xdata_memory(0xF000, FLASHPAGE_SIZE, rambuf);
write_xdata_memory(0xF000 + FLASHPAGE_SIZE, updProcSize, updProc);
debug_instr_3(0x75,0xC7,0x51);
set_pc(0xF000 + FLASHPAGE_SIZE);
cpu_resume();
while (!(read_status() & ST_CPU_HALTED));
}
static void read_flash_page(uint32_t address, __xdata uint8_t *outputData)
{
read_code_memory(address & 0xFFFF,
(address >> 15) & 0x03, FLASHPAGE_SIZE, outputData);
}
static void dbg_readpage(void)
{
read_flash_page(page * 1024, rambuf);
}
static void dbg_writepage(void)
{
uint32_t addr = page*1024;
write_flash_page(addr);
}
uint8_t cons_getch(void)
{
if (rxfifo_in == rxfifo_out)
return 0;
page = rxfifo[rxfifo_out];
if (rxfifo_out + 1 == RXFIFO_SIZE)
rxfifo_out = 0;
else
rxfifo_out++;
return 1;
}
void cons_putc(uint8_t ch)
{
U0DBUF = ch;
while(!(U0CSR & U0CSR_TX_BYTE)); // wait for byte to be transmitted
U0CSR &= ~U0CSR_TX_BYTE; // Clear transmit byte status
}
void uart0_isr(void) __interrupt URX0_VECTOR
{
URX0IF = 0;
// HACK we know the buffer is big enough, as client is waiting for our ACK
// if(rxfifo_in != (( rxfifo_out - 1 + RXFIFO_SIZE) % RXFIFO_SIZE)) // not full
{
rxfifo[rxfifo_in] = U0DBUF;
if (rxfifo_in + 1 == RXFIFO_SIZE)
rxfifo_in = 0;
else
rxfifo_in++;
}
}
void main(void)
{
uint16_t i;
uint8_t n;
// Initialise clocks
SLEEP &= ~SLEEP_OSC_PD; // enable RC oscillator
while( !(SLEEP & SLEEP_XOSC_S) ); // let oscillator stabilise
CLKCON = CLKCON_OSC32 | CLKCON_OSC | TICKSPD_DIV_32 | CLKSPD_DIV_2; // select internal HS RC oscillator
while (!(CLKCON & CLKCON_OSC));
CLKCON = CLKCON_OSC32 | TICKSPD_DIV_32 | CLKSPD_DIV_1; // select external crystal
// while (CLKCON & CLKCON_OSC);
// SLEEP |= SLEEP_OSC_PD; // Disable RC oscillator now that we have an external crystal
rxfifo_in = rxfifo_out = 0;
PERCFG = (PERCFG & ~PERCFG_U0CFG) | PERCFG_U1CFG;
P0SEL |= (1<<3) | (1<<2);
U0CSR = 0x80 | 0x40; // UART, RX on
U0BAUD = 34; // 115200
U0GCR = 13; // 115k2 baud at 13MHz, useful for coming out of sleep. Assumes clkspd_div2 in clkcon for HSRC osc
URX0IF = 0; // No interrupts pending at start
URX0IE = 1; // Serial Rx irqs enabled in system interrupt register
EA = 1;
n = 0;
while(n < sizeof(banner))
cons_putc(banner[n++]);
dbg_init();
i = 0;
while(!cons_getch())
{
if (i-- == 0)
{
cons_putc('P');
}
}
while(1)
{
if (cons_getch())
{
switch(page)
{
case 'e':
while(!cons_getch());
dbg_mass_erase();
goto ack;
break;
case 'p':
while(!cons_getch());
dbg_writepage();
goto ack;
break;
case 'r':
while(!cons_getch());
dbg_readpage();
for (i=0;i<1024;i++)
cons_putc(rambuf[i]);
goto ack;
break;
case 'l':
i = 0;
while(i<1024)
{
while(!cons_getch());
rambuf[i] = page;
i++;
}
goto ack;
break;
case 'j':
WDCTL = (WDCTL & ~WDCTL_INT) | WDCTL_INT_SEC_1; // watchdog on LS RCOSC, ~1s
WDCTL = (WDCTL & ~WDCTL_MODE) | WDCTL_EN; // start
while(1); // reset
break;
ack:
cons_putc(0);
}
}
}
}
+25 -4
View File
@@ -34,6 +34,7 @@ static struct option long_options[] =
{"flash", required_argument, 0, 'f'},
{"device", required_argument, 0, 'd'},
{"timeout", required_argument, 0, 't'},
{"passthrough", no_argument, 0, 'p'},
{0, 0, 0, 0}
};
@@ -49,6 +50,7 @@ void usage(void)
fprintf(stderr, " --console -c Connect console to serial port on device\n");
fprintf(stderr, " --flash=file.hex -f file.hex Reflash device with intel hex file\n");
fprintf(stderr, " --timeout=n -t n Search for bootload string for n seconds\n");
fprintf(stderr, " --passthrough -p Program remote device over passthrough\n");
}
static bool opt_console = false;
@@ -57,6 +59,7 @@ static int opt_timeout = 10;
static bool opt_device = false;
static char *flash_filename = NULL;
static char *device_name = NULL;
static bool opt_passthrough = 0;
#ifndef WIN32
static struct termios orig_termios;
@@ -69,7 +72,7 @@ int parse_options(int argc, char **argv)
while(1)
{
c = getopt_long (argc, argv, "hcf:d:t:", long_options, &option_index);
c = getopt_long (argc, argv, "hcf:d:t:p", long_options, &option_index);
if (c == -1)
break;
switch(c)
@@ -77,6 +80,9 @@ int parse_options(int argc, char **argv)
case 'h':
return 1;
break;
case 'p':
opt_passthrough = 1;
break;
case 't':
opt_timeout = atoi(optarg);
break;
@@ -352,11 +358,15 @@ int read_page(int fd, uint8_t page, uint8_t *data)
return 0;
}
static int already_erased = 0; // passthrough programmer only supports mass erase
int erase_page(int fd, uint8_t page)
{
char cmd = 'e';
char rsp;
if (already_erased && opt_passthrough)
return 0;
if (serialWrite(fd, &cmd, 1) <= 0)
return 1;
@@ -369,6 +379,8 @@ int erase_page(int fd, uint8_t page)
return 1;
}
already_erased = 1;
return 0;
}
@@ -457,7 +469,8 @@ int wait_for_bootloader(int fd, int timeout)
gettimeofday(&start, NULL);
serialWrite(fd, "+++", 3);
if (!opt_passthrough)
serialWrite(fd, "+++", 3);
printf("Waiting %ds for bootloader, reset board now\n", timeout);
@@ -479,8 +492,16 @@ int wait_for_bootloader(int fd, int timeout)
else
if (rc == 1)
{
if (c == 'B' && prev_c == 'B')
break;
if (opt_passthrough)
{
if (c == 'P' && prev_c == 'P')
break;
}
else
{
if (c == 'B' && prev_c == 'B')
break;
}
prev_c = c;
}
}
View File
File renamed without changes.
+1283
View File
File diff suppressed because it is too large. Load diff
View File
File renamed without changes.
View File
File renamed without changes.