2020-09-28

CC3x20 Embedded Programming in macOS

To use TI SimpleLink Wi-Fi CC3x20, we have to program the serial flash. Tere are two ways to go:

  1. Use UniFlash to generate the image and program directly.
  2. Use Embedded Programming.
UniFlash requires certain hardware to be used, for example, CC3220 launchpad. For devices such as CC3120, there isn't JTAG interface. So, UniFlash has to go through UART interface. But only the UART interface with JTAG debugger or the UART on CC31XXEMUBOOST are supported.

For mass production consideration, it is better to go through the Embedded Programming method. TI has provided a Python script. But it can only run under Windows. For users like me, we use macOS and don't like to switch to Windows just for programming the image. So, I have to figure a way to use Embedded Programming under macOS.

For CC3x20 to enter boot-loader mode, the CC3x20.RX pin must be held in low and then pull RESET pin low/high. My idea is to pull RESET pin by the host RTS pin and pull host TX pin by using the tcsendbreak() API.

I have designed a C++ program by using POXIS termios APIs. But the termios API tcsendbreak() can't generate required timing for "break signal". Btw, the RTS timing is seriously affected by tcsendbreak() call. Anyway, I just can't get a proper timing.

Then, I give-up termios APIs. I think I can control RTS and break signal precisely by using FTDI D2XX driver. That's it. It just works!

I would like to share the code here in case you also need it.

bool CC3X20EP::enterBootloaderMode()
{
printf("%s()\n", __FUNCTION__);

// Flush the rx line (CC3x20 write line)
FT_Purge(fd, FT_PURGE_RX);

// Send a break signal(sending continuous spacing values, no start or stop bits) on the CC3x20 UART RX line.
// The CC3x20 device must sense this break signal during power up.
// The "duration" argument is ignored in macOS.
// tcsendbreak() will send break signal for 250ms ~ 500ms, actual measured 400ms.
FT_SetBreakOn(fd);

// Power on the device (or reset it if it is already up and running).
// We can connect RTS pin to CC3x20.nHIB/nRESET and then pull RTS low/high.
// The minimum pulse time is 10ms for nHIB and 200ms for nRESET.
// See CC3120 datasheet.
FT_SetRts(fd);
msleep(200);
FT_ClrRts(fd);

// There seems garbages after nHIB is released
FT_Purge(fd, FT_PURGE_RX);

// CC3x20 sends an acknowledgment indication as described in Ack (0x00, 0xCC).
// CC3x20 should send ACK back in less than 300ms.
bool isAck = false;
uint16_t ack;
if (rx((uint8_t*)&ack, 2, 500) > 0) {
if (ack == ACK) {
isAck = true;
} else {
printf("%s() error! ack not valid\n", __FUNCTION__);
}
} else {
printf("%s() timedout to get ack\n", __FUNCTION__);
}

// On receiving the acknowledgment indication from the CC3x20 device,
// the main processor stops sending the break signal and flushes the UART lines.
FT_SetBreakOff(fd);

if (!isAck) {
return false;
}

// At this point, CC3x20 is ready to receive any command.
// The main processor has 5 seconds to send any command. Failing to do so before
// the time-out expires results in the CC3x20 device initializing normally
// (aborting bootloader mode).
FT_Purge(fd, FT_PURGE_RX);

// 6. The main processor sends the Get Storage List command.
// The CC3x20 device responds with an Ack followed by a 1-byte storage list bitmap.
if (!getStorageList()) {
return false;
}
printf("%s() storage list bitmap: 0x%02X\n", __FUNCTION__, storageBitmap);

return true;
}