diff --git a/CCLoader/src/CCLoader.ino b/CCLoader/src/CCLoader.ino
index def5263..75f6388 100644
--- a/CCLoader/src/CCLoader.ino
+++ b/CCLoader/src/CCLoader.ino
@@ -162,7 +162,7 @@ unsigned char read_debug_byte(void)
if(HIGH == digitalRead(DD))
{
data |= 0x01;
- }
+ }
digitalWrite(DC, LOW); // DC low
}
return data;
@@ -520,27 +520,34 @@ void ProgrammerInit(void)
digitalWrite(LED, LOW);
}
-void setup()
-{
- ProgrammerInit();
+void setup()
+{
+ ProgrammerInit();
Serial.begin(115200);
- // If using Leonado as programmer,
+ // If using Leonado as programmer,
//it should add below code,otherwise,comment it.
while(!Serial);
}
-void loop()
+void loop()
{
unsigned char chip_id = 0;
unsigned char debug_config = 0;
unsigned char Continue = 0;
unsigned char Verify = 0;
-
+
+ // Drop any stale bytes (e.g. boot-time noise) sitting in the RX buffer
+ // ahead of a real handshake attempt from the host.
+ while(Serial.available()) Serial.read();
+
while(!Continue) // Wait for starting
- {
-
- if(Serial.available()==2)
- {
+ {
+
+ if(Serial.available()>=2) // was strictly ==2: a single stray byte
+ // ahead of the real handshake could make
+ // this condition never trigger, hanging
+ // forever.
+ {
if(Serial.read() == SBEGIN)
{
Verify = Serial.read();
@@ -555,43 +562,43 @@ void loop()
debug_init();
chip_id = read_chip_id();
- if(chip_id == 0)
+ if(chip_id == 0)
{
- Serial.write(ERRO);
+ Serial.write(ERRO);
return; // No chip detected, run loop again.
}
-
+
RunDUP();
debug_init();
-
+
chip_erase();
RunDUP();
debug_init();
-
+
// Switch DUP to external crystal osc. (XOSC) and wait for it to be stable.
// This is recommended if XOSC is available during programming. If
// XOSC is not available, comment out these two lines.
write_xdata_memory(DUP_CLKCONCMD, 0x80);
while (read_xdata_memory(DUP_CLKCONSTA) != 0x80);//0x80)
-
+
// Enable DMA (Disable DMA_PAUSE bit in debug configuration)
debug_config = 0x22;
debug_command(CMD_WR_CONFIG, &debug_config, 1);
-
+
// Program data (start address must be word aligned [32 bit])
Serial.write(SRSP); // Request data blocks
- digitalWrite(LED, HIGH);
+ digitalWrite(LED, HIGH);
unsigned char Done = 0;
unsigned char State = WAITING;
- unsigned char rxBuf[514];
+ unsigned char rxBuf[514];
unsigned int BufIndex = 0;
unsigned int addr = 0x0000;
while(!Done)
{
while(Serial.available())
{
- unsigned char ch;
- ch = Serial.read();
+ unsigned char ch;
+ ch = Serial.read();
switch (State)
{
// Bootloader is waiting for a new block, each block begin with a flag byte
@@ -606,15 +613,15 @@ void loop()
Done = 1; // Exit while(1) in main function
}
break;
- }
- // Bootloader is receiving block data
+ }
+ // Bootloader is receiving block data
case RECEIVING:
- {
+ {
rxBuf[BufIndex] = ch;
- BufIndex++;
+ BufIndex++;
if (BufIndex == 514) // If received one block, write it to flash
{
- BufIndex = 0;
+ BufIndex = 0;
uint16_t CheckSum = 0x0000;
for(unsigned int i=0; i<512; i++)
{
@@ -624,43 +631,42 @@ void loop()
if(CheckSum_t != CheckSum)
{
State = WAITING;
- Serial.write(ERRO);
+ Serial.write(ERRO);
chip_erase();
return;
- }
- write_flash_memory_block(rxBuf, addr, 512); // src, address, count
+ }
+ write_flash_memory_block(rxBuf, addr, 512); // src, address, count
if(Verify)
{
unsigned char bank = addr / (512 * 16);
unsigned int offset = (addr % (512 * 16)) * 4;
unsigned char read_data[512];
- read_flash_memory_block(bank, offset, 512, read_data); // Bank, address, count, dest.
- for(unsigned int i = 0; i < 512; i++)
+ read_flash_memory_block(bank, offset, 512, read_data); // Bank, address, count, dest.
+ for(unsigned int i = 0; i < 512; i++)
{
- if(read_data[i] != rxBuf[i])
+ if(read_data[i] != rxBuf[i])
{
// Fail
State = WAITING;
- Serial.write(ERRO);
+ Serial.write(ERRO);
chip_erase();
return;
}
}
}
- addr += (unsigned int)128;
+ addr += (unsigned int)128;
State = WAITING;
Serial.write(SRSP);
}
break;
- }
+ }
default:
break;
}
}
}
-
+
digitalWrite(LED, LOW);
RunDUP();
}
-
diff --git a/README.md b/README.md
index 0c1e4ef..c751754 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,10 @@ CCLoader
Burn CC25xx/HM10 firmware using a NodeMCU or Wemos D1 mini.
+Known issue: CCLoader hangs with no response after a cold USB reconnect.
+==========================
+On ESP8266/NodeMCU-style boards (e.g. Wemos D1 Mini), the DTR/RTS auto-reset circuit that resets the chip when the serial port opens doesn't always reliably boot it back into normal run mode after a full USB unplug/replug — it can leave the chip stuck in its ROM bootloader, where it will never respond to CCLoader no matter how long you wait. This is a hardware/driver quirk, not a CCLoader bug, and a plain reset button press doesn't fix it either. The fix is to let esptool perform its own (more robust) reset handling once before running CCLoader: run `esptool --port /dev/ttyXXX chip_id` (a quick, read-only command) after any reconnect, then run CCLoader normally. This is only needed after a physical reconnect/power-cycle — it's not required right after flashing, since the upload process already leaves the board in a working state.
+
Flashing CC2530 or CC2531
==========================
Use the files provided in folder [`Bin`](/Bin). The BIN files are already converted and ready to flash with CCLoader
diff --git a/SourceCode/Linux/main.c b/SourceCode/Linux/main.c
index b6755a1..c229a00 100644
--- a/SourceCode/Linux/main.c
+++ b/SourceCode/Linux/main.c
@@ -12,6 +12,7 @@ extern "C" {
#include
#include
#include
+#include
int RS232_OpenComport(int, int);
int RS232_PollComport(int, unsigned char *, int);
@@ -54,13 +55,28 @@ char comports[30][16]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev
void ProcessProgram(void);
+static long now_ms(void)
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+}
+
+/* Timestamp (ms) of the last byte we received, used to detect a stalled
+ * handshake and retry instead of hanging forever - the board never re-sends
+ * SBEGIN on its own if the first attempt is dropped. */
+static long last_rx_ms = 0;
+static int sbegin_retries = 0;
+#define SBEGIN_RETRY_INTERVAL_MS 1000
+#define SBEGIN_MAX_RETRIES 10
+
/*
* argv[0]----.exe file name
* argv[1]----ComPort number
* argv[2]----file path
*/
int main(int arg, char *argv[])
-{
+{
int fLen = 0;
int device = 0;
@@ -111,7 +127,7 @@ int main(int arg, char *argv[])
char form[5] = ".bin";
char format[5] = " ";
fLen = strlen(argv[2]);
- if(fLen < 5)
+ if(fLen < 5)
{
printf("File path is invalid!\n");
return 0; // file path is not valid
@@ -119,7 +135,7 @@ int main(int arg, char *argv[])
format[3] = argv[2][fLen-1];
format[2] = argv[2][fLen-2];
format[1] = argv[2][fLen-3];
- format[0] = argv[2][fLen-4];
+ format[0] = argv[2][fLen-4];
if(0 != strcmp(form, format))
{
printf("File format must be .bin");
@@ -147,10 +163,19 @@ int main(int arg, char *argv[])
{
BlkTot = fsize / 512;
}
-
+
printf("Block total: %d\n", BlkTot);
BlkNum = 0;
+ /* Opening the port (RS232_OpenComport() above) and toggling DTR/RTS can
+ * trigger a reset on ESP8266/NodeMCU-style auto-reset boards. Give the
+ * board a moment to finish rebooting and discard any boot-time noise
+ * before starting the handshake, instead of racing it. */
+ printf("Waiting for device reset to settle...\n");
+ fflush(stdout);
+ usleep(2000000); /* 2s */
+ tcflush(Cport[com], TCIFLUSH);
+
printf("Enable transmission...\n");
unsigned char buf[2] = {SBEGIN, 0}; // Enable transmission, do not verify
if(RS232_SendBuf(com, buf, 2) != 2)
@@ -166,10 +191,38 @@ int main(int arg, char *argv[])
{
printf("Request sent already! Waiting for respond...\n");
}
-
+ last_rx_ms = now_ms();
+
while(!end)
{
ProcessProgram();
+
+ /* The board never re-sends SBEGIN on its own, so if the first
+ * attempt is dropped the original code just polled forever with no
+ * feedback. Resend periodically, then give up cleanly instead of
+ * hanging indefinitely. */
+ if(!DownloadProgress && !end)
+ {
+ long t = now_ms();
+ if(t - last_rx_ms > SBEGIN_RETRY_INTERVAL_MS)
+ {
+ sbegin_retries++;
+ if(sbegin_retries > SBEGIN_MAX_RETRIES)
+ {
+ printf("\nNo response after %d attempts (%d ms) - giving up.\n"
+ "Check the port/wiring, and that the device is running "
+ "(not stuck in its bootloader - reset it with esptool.py "
+ "if needed).\n",
+ sbegin_retries, SBEGIN_RETRY_INTERVAL_MS * SBEGIN_MAX_RETRIES);
+ fclose(pfile);
+ RS232_CloseComport(com);
+ return 1;
+ }
+ RS232_SendBuf(com, buf, 2);
+ last_rx_ms = t;
+ }
+ }
+ usleep(2000); /* don't busy-spin the CPU at 100% while polling */
}
printf("Program successfully!\n");
BlkNum = 0;
@@ -189,6 +242,8 @@ void ProcessProgram()
len = RS232_PollComport(com, &rx, 1);
if(len > 0)
{
+ last_rx_ms = now_ms();
+ sbegin_retries = 0;
switch(rx)
{
case SRSP:
@@ -202,7 +257,7 @@ void ProcessProgram()
else
{
if(BlkNum == 0)
- {
+ {
printf("Begin programming...\n");
}
DownloadProgress = 1;
@@ -223,7 +278,7 @@ void ProcessProgram()
{
fread(buf+1, 512, 1, pfile);
}
-
+
unsigned short CheckSum = 0x0000;
//unsigned int i;
@@ -233,7 +288,7 @@ void ProcessProgram()
}
buf[513] = (CheckSum >> 8) & 0x00FF;
buf[514] = CheckSum & 0x00FF;
-
+
RS232_SendBuf(com, buf, 515);
BlkNum++;
printf("%d ", BlkNum);
@@ -535,4 +590,3 @@ void RS232_disableRTS(int comport_number)
#ifdef __cplusplus
} /* extern "C" */
#endif
-