MBED board as programmer for CC254x chips. Visit https://github.com/RedBearLab/CCLoader for more details.

Dependencies:   mbed

Devices running Android 8.0 (or newer) are not able to discover cheap CC41-A Bluetooth LE modules anymore - read "Should you throw away your CC41 HM-10 clones now that Android 8 is here?".

Since RedBearLab figured out how to use Arduino as programmer for CC254x chips a simple fix is flashing a genuine HM-10 firmware to CC41-A modules. Visit Bluetooth BLE Adventures to learn how to do it.

To use an Mbed board rather than Arduino this repository provides RedBearLab's CCLoader ported to Mbed. After compiling and flashing, it converts an Mbed board to a CC254x programmer.

Usage:

  • Compile and download this program to an Mbed board equipped with Arduino header.
  • Keep the Mbed board connected to the PC over a USB cable.
  • Connect the Mbed board to the CC41-A BLE module as shown in the picture below: /media/uploads/hudakz/ccloader1.png
  • Run RedBearLab's CCLoader.exe on your PC to flash the CC41-A module using the MBED board as a programmer.
    For example:

> ccloader_x86_64 3 cc2541hm10v540.bin 1
Committer:
hudakz
Date:
Wed Jun 19 16:34:56 2019 +0000
Revision:
1:c874ea9c1afb
Parent:
0:0834641c241a
Burn CC254x firmware using an MBED board.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:0834641c241a 1 /*
hudakz 0:0834641c241a 2
hudakz 0:0834641c241a 3 Copyright (c) 2012-2014 RedBearLab
hudakz 0:0834641c241a 4
hudakz 0:0834641c241a 5 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
hudakz 0:0834641c241a 6
hudakz 0:0834641c241a 7 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
hudakz 0:0834641c241a 8
hudakz 0:0834641c241a 9 Ported to MBED by Zoltan Hudak 2019
hudakz 0:0834641c241a 10
hudakz 0:0834641c241a 11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
hudakz 0:0834641c241a 12
hudakz 0:0834641c241a 13 */
hudakz 0:0834641c241a 14 /******************************************************************************
hudakz 0:0834641c241a 15 * INCLUDES
hudakz 0:0834641c241a 16 */
hudakz 0:0834641c241a 17 #include "mbed.h"
hudakz 0:0834641c241a 18
hudakz 0:0834641c241a 19 /******************************************************************************
hudakz 0:0834641c241a 20 * DEFINES
hudakz 0:0834641c241a 21 */
hudakz 0:0834641c241a 22 // Start addresses on DUP (Increased buffer size improves performance)
hudakz 0:0834641c241a 23 #define ADDR_BUF0 0x0000 // Buffer (512 bytes)
hudakz 0:0834641c241a 24 #define ADDR_DMA_DESC_0 0x0200 // DMA descriptors (8 bytes)
hudakz 0:0834641c241a 25 #define ADDR_DMA_DESC_1 (ADDR_DMA_DESC_0 + 8)
hudakz 0:0834641c241a 26
hudakz 0:0834641c241a 27 // DMA channels used on DUP
hudakz 0:0834641c241a 28 #define CH_DBG_TO_BUF0 0x01 // Channel 0
hudakz 0:0834641c241a 29 #define CH_BUF0_TO_FLASH 0x02 // Channel 1
hudakz 0:0834641c241a 30
hudakz 0:0834641c241a 31 // Debug commands
hudakz 0:0834641c241a 32 #define CMD_CHIP_ERASE 0x10
hudakz 0:0834641c241a 33 #define CMD_WR_CONFIG 0x19
hudakz 0:0834641c241a 34 #define CMD_RD_CONFIG 0x24
hudakz 0:0834641c241a 35 #define CMD_READ_STATUS 0x30
hudakz 0:0834641c241a 36 #define CMD_RESUME 0x4C
hudakz 0:0834641c241a 37 #define CMD_DEBUG_INSTR_1B (0x54|1)
hudakz 0:0834641c241a 38 #define CMD_DEBUG_INSTR_2B (0x54|2)
hudakz 0:0834641c241a 39 #define CMD_DEBUG_INSTR_3B (0x54|3)
hudakz 0:0834641c241a 40 #define CMD_BURST_WRITE 0x80
hudakz 0:0834641c241a 41 #define CMD_GET_CHIP_ID 0x68
hudakz 0:0834641c241a 42
hudakz 0:0834641c241a 43 // Debug status bitmasks
hudakz 0:0834641c241a 44 #define STATUS_CHIP_ERASE_BUSY_BM 0x80 // New debug interface
hudakz 0:0834641c241a 45 #define STATUS_PCON_IDLE_BM 0x40
hudakz 0:0834641c241a 46 #define STATUS_CPU_HALTED_BM 0x20
hudakz 0:0834641c241a 47 #define STATUS_PM_ACTIVE_BM 0x10
hudakz 0:0834641c241a 48 #define STATUS_HALT_STATUS_BM 0x08
hudakz 0:0834641c241a 49 #define STATUS_DEBUG_LOCKED_BM 0x04
hudakz 0:0834641c241a 50 #define STATUS_OSC_STABLE_BM 0x02
hudakz 0:0834641c241a 51 #define STATUS_STACK_OVERFLOW_BM 0x01
hudakz 0:0834641c241a 52
hudakz 0:0834641c241a 53 // DUP registers (XDATA space address)
hudakz 0:0834641c241a 54 #define DUP_DBGDATA 0x6260 // Debug interface data buffer
hudakz 0:0834641c241a 55 #define DUP_FCTL 0x6270 // Flash controller
hudakz 0:0834641c241a 56 #define DUP_FADDRL 0x6271 // Flash controller addr
hudakz 0:0834641c241a 57 #define DUP_FADDRH 0x6272 // Flash controller addr
hudakz 0:0834641c241a 58 #define DUP_FWDATA 0x6273 // Clash controller data buffer
hudakz 0:0834641c241a 59 #define DUP_CLKCONSTA 0x709E // Sys clock status
hudakz 0:0834641c241a 60 #define DUP_CLKCONCMD 0x70C6 // Sys clock configuration
hudakz 0:0834641c241a 61 #define DUP_MEMCTR 0x70C7 // Flash bank xdata mapping
hudakz 0:0834641c241a 62 #define DUP_DMA1CFGL 0x70D2 // Low byte, DMA config ch. 1
hudakz 0:0834641c241a 63 #define DUP_DMA1CFGH 0x70D3 // Hi byte , DMA config ch. 1
hudakz 0:0834641c241a 64 #define DUP_DMA0CFGL 0x70D4 // Low byte, DMA config ch. 0
hudakz 0:0834641c241a 65 #define DUP_DMA0CFGH 0x70D5 // Low byte, DMA config ch. 0
hudakz 0:0834641c241a 66 #define DUP_DMAARM 0x70D6 // DMA arming register
hudakz 0:0834641c241a 67
hudakz 0:0834641c241a 68 // Utility macros
hudakz 0:0834641c241a 69 //! Low nibble of 16bit variable
hudakz 0:0834641c241a 70 #define LOBYTE(w) ((unsigned char)(w))
hudakz 0:0834641c241a 71 //! High nibble of 16bit variable
hudakz 0:0834641c241a 72 #define HIBYTE(w) ((unsigned char)(((unsigned short)(w) >> 8) & 0xFF))
hudakz 0:0834641c241a 73
hudakz 0:0834641c241a 74 // Commands to Bootloader
hudakz 0:0834641c241a 75 #define SBEGIN 0x01
hudakz 0:0834641c241a 76 #define SDATA 0x02
hudakz 0:0834641c241a 77 #define SRSP 0x03
hudakz 0:0834641c241a 78 #define SEND 0x04
hudakz 0:0834641c241a 79 #define ERRO 0x05
hudakz 0:0834641c241a 80 #define WAITING 0x00
hudakz 0:0834641c241a 81 #define RECEIVING 0x01
hudakz 0:0834641c241a 82
hudakz 0:0834641c241a 83 // Debug control pins & the indicate LED
hudakz 0:0834641c241a 84 DigitalOut reset(D4);
hudakz 0:0834641c241a 85 DigitalOut dc(D5);
hudakz 0:0834641c241a 86 DigitalInOut dd(D6);
hudakz 0:0834641c241a 87 DigitalOut led(LED1);
hudakz 0:0834641c241a 88 Serial serial(USBTX, USBRX);
hudakz 0:0834641c241a 89
hudakz 0:0834641c241a 90 /******************************************************************************
hudakz 0:0834641c241a 91 VARIABLES*/
hudakz 0:0834641c241a 92 //! DUP DMA descriptor
hudakz 0:0834641c241a 93 const unsigned char dmaDesc0[8] =
hudakz 0:0834641c241a 94 {
hudakz 0:0834641c241a 95 // Debug Interface -> Buffer
hudakz 0:0834641c241a 96 HIBYTE(DUP_DBGDATA), // src[15:8]
hudakz 0:0834641c241a 97 LOBYTE(DUP_DBGDATA), // src[7:0]
hudakz 0:0834641c241a 98 HIBYTE(ADDR_BUF0), // dest[15:8]
hudakz 0:0834641c241a 99 LOBYTE(ADDR_BUF0), // dest[7:0]
hudakz 0:0834641c241a 100 0, // len[12:8] - filled in later
hudakz 0:0834641c241a 101 0, // len[7:0]
hudakz 0:0834641c241a 102 31, // trigger: DBG_BW
hudakz 0:0834641c241a 103 0x11 // increment destination
hudakz 0:0834641c241a 104 };
hudakz 0:0834641c241a 105 //! DUP DMA descriptor
hudakz 0:0834641c241a 106 const unsigned char dmaDesc1[8] =
hudakz 0:0834641c241a 107 {
hudakz 0:0834641c241a 108 // Buffer -> Flash controller
hudakz 0:0834641c241a 109 HIBYTE(ADDR_BUF0), // src[15:8]
hudakz 0:0834641c241a 110 LOBYTE(ADDR_BUF0), // src[7:0]
hudakz 0:0834641c241a 111 HIBYTE(DUP_FWDATA), // dest[15:8]
hudakz 0:0834641c241a 112 LOBYTE(DUP_FWDATA), // dest[7:0]
hudakz 0:0834641c241a 113 0, // len[12:8] - filled in later
hudakz 0:0834641c241a 114 0, // len[7:0]
hudakz 0:0834641c241a 115 18, // trigger: FLASH
hudakz 0:0834641c241a 116 0x42, // increment source
hudakz 0:0834641c241a 117 };
hudakz 0:0834641c241a 118
hudakz 0:0834641c241a 119 /**************************************************************************/
hudakz 0:0834641c241a 120 /**
hudakz 0:0834641c241a 121 * @brief Writes a byte on the debug interface. Requires DD to be
hudakz 0:0834641c241a 122 * output when function is called.
hudakz 0:0834641c241a 123 * @param data Byte to write
hudakz 0:0834641c241a 124 * @return None.
hudakz 0:0834641c241a 125 ******************************************************************************/
hudakz 0:0834641c241a 126 #pragma inline
hudakz 0:0834641c241a 127 void writeDebugByte(unsigned char data)
hudakz 0:0834641c241a 128 {
hudakz 0:0834641c241a 129 unsigned char i;
hudakz 0:0834641c241a 130 for (i = 0; i < 8; i++) {
hudakz 0:0834641c241a 131 // Set clock high and put data on DD line
hudakz 0:0834641c241a 132 dc = 1;
hudakz 0:0834641c241a 133 if (data & 0x80) {
hudakz 0:0834641c241a 134 dd = 1;
hudakz 0:0834641c241a 135 }
hudakz 0:0834641c241a 136 else {
hudakz 0:0834641c241a 137 dd = 0;
hudakz 0:0834641c241a 138 }
hudakz 0:0834641c241a 139
hudakz 0:0834641c241a 140 data <<= 1;
hudakz 0:0834641c241a 141 dc = 0; // set clock low (DUP capture flank)
hudakz 0:0834641c241a 142 }
hudakz 0:0834641c241a 143 }
hudakz 0:0834641c241a 144
hudakz 0:0834641c241a 145 /**************************************************************************/
hudakz 0:0834641c241a 146 /**
hudakz 0:0834641c241a 147 * @brief Reads a byte from the debug interface. Requires DD to be
hudakz 0:0834641c241a 148 * input when function is called.
hudakz 0:0834641c241a 149 * @return Returns the byte read.
hudakz 0:0834641c241a 150 ******************************************************************************/
hudakz 0:0834641c241a 151 #pragma inline
hudakz 0:0834641c241a 152 unsigned char readDebugByte(void)
hudakz 0:0834641c241a 153 {
hudakz 0:0834641c241a 154 unsigned char i;
hudakz 0:0834641c241a 155 unsigned char data = 0x00;
hudakz 0:0834641c241a 156
hudakz 0:0834641c241a 157 for (i = 0; i < 8; i++) {
hudakz 0:0834641c241a 158 dc = 1; // DC high
hudakz 0:0834641c241a 159 data <<= 1;
hudakz 0:0834641c241a 160 if (dd == 1) {
hudakz 0:0834641c241a 161 data |= 0x01;
hudakz 0:0834641c241a 162 }
hudakz 0:0834641c241a 163
hudakz 0:0834641c241a 164 dc = 0; // DC low
hudakz 0:0834641c241a 165 }
hudakz 0:0834641c241a 166
hudakz 0:0834641c241a 167 return data;
hudakz 0:0834641c241a 168 }
hudakz 0:0834641c241a 169
hudakz 0:0834641c241a 170 /**************************************************************************/
hudakz 0:0834641c241a 171 /**
hudakz 0:0834641c241a 172 * @brief Function waits for DUP to indicate that it is ready. The DUP will
hudakz 0:0834641c241a 173 * pulls DD line low when it is ready. Requires DD to be input when
hudakz 0:0834641c241a 174 * function is called.
hudakz 0:0834641c241a 175 * @return Returns 0 if function timed out waiting for DD line to go low
hudakz 0:0834641c241a 176 * @return Returns 1 when DUP has indicated it is ready.
hudakz 0:0834641c241a 177 ******************************************************************************/
hudakz 0:0834641c241a 178 #pragma inline
hudakz 0:0834641c241a 179 unsigned char waitDupReady(void)
hudakz 0:0834641c241a 180 {
hudakz 0:0834641c241a 181 // DUP pulls DD low when ready
hudakz 0:0834641c241a 182 unsigned int count = 0;
hudakz 0:0834641c241a 183 while ((dd == 1) && count < 16) {
hudakz 0:0834641c241a 184 // Clock out 8 bits before checking if DD is low again
hudakz 0:0834641c241a 185 readDebugByte();
hudakz 0:0834641c241a 186 count++;
hudakz 0:0834641c241a 187 }
hudakz 0:0834641c241a 188
hudakz 0:0834641c241a 189 return(count == 16) ? 0 : 1;
hudakz 0:0834641c241a 190 }
hudakz 0:0834641c241a 191
hudakz 0:0834641c241a 192 /**************************************************************************/
hudakz 0:0834641c241a 193
hudakz 0:0834641c241a 194 /**
hudakz 0:0834641c241a 195 * @brief Issues a command on the debug interface. Only commands that return
hudakz 0:0834641c241a 196 * one output byte are supported.
hudakz 0:0834641c241a 197 * @param cmd Command byte
hudakz 0:0834641c241a 198 * @param cmd_bytes Pointer to the array of data bytes following the
hudakz 0:0834641c241a 199 * command byte [0-3]
hudakz 0:0834641c241a 200 * @param num_cmd_bytes The number of data bytes (input to DUP) [0-3]
hudakz 0:0834641c241a 201 * @return Data returned by command
hudakz 0:0834641c241a 202 ******************************************************************************/
hudakz 0:0834641c241a 203 unsigned char debugCommand(unsigned char cmd, unsigned char* cmd_bytes, unsigned short num_cmd_bytes)
hudakz 0:0834641c241a 204 {
hudakz 0:0834641c241a 205 unsigned short i;
hudakz 0:0834641c241a 206 unsigned char output = 0;
hudakz 0:0834641c241a 207 // Make sure DD is output
hudakz 0:0834641c241a 208 dd.output();
hudakz 0:0834641c241a 209 // Send command
hudakz 0:0834641c241a 210 writeDebugByte(cmd);
hudakz 0:0834641c241a 211 // Send bytes
hudakz 0:0834641c241a 212 for (i = 0; i < num_cmd_bytes; i++) {
hudakz 0:0834641c241a 213 writeDebugByte(cmd_bytes[i]);
hudakz 0:0834641c241a 214 }
hudakz 0:0834641c241a 215
hudakz 0:0834641c241a 216 // Set DD as input
hudakz 0:0834641c241a 217 dd.input();
hudakz 0:0834641c241a 218 dd.mode(PullUp);
hudakz 0:0834641c241a 219 // Wait for data to be ready
hudakz 0:0834641c241a 220 waitDupReady();
hudakz 0:0834641c241a 221 // Read returned byte
hudakz 0:0834641c241a 222 output = readDebugByte();
hudakz 0:0834641c241a 223 // Set DD as output
hudakz 0:0834641c241a 224 dd.output();
hudakz 0:0834641c241a 225
hudakz 0:0834641c241a 226 return output;
hudakz 0:0834641c241a 227 }
hudakz 0:0834641c241a 228
hudakz 0:0834641c241a 229 /**************************************************************************/
hudakz 0:0834641c241a 230
hudakz 0:0834641c241a 231 /**
hudakz 0:0834641c241a 232 * @brief Resets the DUP into debug mode. Function assumes that
hudakz 0:0834641c241a 233 * the programmer I/O has already been configured using e.g.
hudakz 0:0834641c241a 234 * ProgrammerInit().
hudakz 0:0834641c241a 235 * @return None.
hudakz 0:0834641c241a 236 ******************************************************************************/
hudakz 0:0834641c241a 237 void debugInit(void)
hudakz 0:0834641c241a 238 {
hudakz 0:0834641c241a 239 volatile unsigned char i;
hudakz 0:0834641c241a 240
hudakz 0:0834641c241a 241 // Send two flanks on DC while keeping RESET_N low
hudakz 0:0834641c241a 242 // All low (incl. RESET_N)
hudakz 0:0834641c241a 243 dd = 0;
hudakz 0:0834641c241a 244 dc = 0;
hudakz 0:0834641c241a 245 reset = 0;
hudakz 0:0834641c241a 246 wait_ms(10); // Wait
hudakz 0:0834641c241a 247 dc = 1; // DC high
hudakz 0:0834641c241a 248 wait_ms(10); // Wait
hudakz 0:0834641c241a 249 dc = 0; // DC low
hudakz 0:0834641c241a 250 wait_ms(10); // Wait
hudakz 0:0834641c241a 251 dc = 1; // DC high
hudakz 0:0834641c241a 252 wait_ms(10); // Wait
hudakz 0:0834641c241a 253 dc = 0; // DC low
hudakz 0:0834641c241a 254 wait_ms(10); // Wait
hudakz 0:0834641c241a 255 reset = 1; // Release RESET_N
hudakz 0:0834641c241a 256 wait_ms(10); // Wait
hudakz 0:0834641c241a 257 }
hudakz 0:0834641c241a 258
hudakz 0:0834641c241a 259 /**************************************************************************/
hudakz 0:0834641c241a 260
hudakz 0:0834641c241a 261 /**
hudakz 0:0834641c241a 262 * @brief Reads the chip ID over the debug interface using the
hudakz 0:0834641c241a 263 * GET_CHIP_ID command.
hudakz 0:0834641c241a 264 * @return Returns the chip id returned by the DUP
hudakz 0:0834641c241a 265 ******************************************************************************/
hudakz 0:0834641c241a 266 unsigned char readChipId(void)
hudakz 0:0834641c241a 267 {
hudakz 0:0834641c241a 268 unsigned char id = 0;
hudakz 0:0834641c241a 269
hudakz 0:0834641c241a 270 // Make sure DD is output
hudakz 0:0834641c241a 271 dd.output();
hudakz 0:0834641c241a 272 wait_ms(1);
hudakz 0:0834641c241a 273 // Send command
hudakz 0:0834641c241a 274 writeDebugByte(CMD_GET_CHIP_ID);
hudakz 0:0834641c241a 275 // Set DD as input
hudakz 0:0834641c241a 276 dd.input();
hudakz 0:0834641c241a 277 dd.mode(PullUp);
hudakz 0:0834641c241a 278 wait_ms(1);
hudakz 0:0834641c241a 279 // Wait for data to be ready
hudakz 0:0834641c241a 280 if (waitDupReady() == 1) {
hudakz 0:0834641c241a 281 // Read ID and revision
hudakz 0:0834641c241a 282 id = readDebugByte(); // ID
hudakz 0:0834641c241a 283 readDebugByte(); // Revision (discard)
hudakz 0:0834641c241a 284 }
hudakz 0:0834641c241a 285
hudakz 0:0834641c241a 286 // Set DD as output
hudakz 0:0834641c241a 287 dd.output();
hudakz 0:0834641c241a 288
hudakz 0:0834641c241a 289 return id;
hudakz 0:0834641c241a 290 }
hudakz 0:0834641c241a 291
hudakz 0:0834641c241a 292 /**************************************************************************/
hudakz 0:0834641c241a 293
hudakz 0:0834641c241a 294 /**
hudakz 0:0834641c241a 295 * @brief Sends a block of data over the debug interface using the
hudakz 0:0834641c241a 296 * BURST_WRITE command.
hudakz 0:0834641c241a 297 * @param src Pointer to the array of input bytes
hudakz 0:0834641c241a 298 * @param num_bytes The number of input bytes
hudakz 0:0834641c241a 299 * @return None.
hudakz 0:0834641c241a 300 ******************************************************************************/
hudakz 0:0834641c241a 301 void burstWriteBlock(unsigned char* src, unsigned short num_bytes)
hudakz 0:0834641c241a 302 {
hudakz 0:0834641c241a 303 unsigned short i;
hudakz 0:0834641c241a 304
hudakz 0:0834641c241a 305 // Make sure DD is output
hudakz 0:0834641c241a 306 dd.output();
hudakz 0:0834641c241a 307
hudakz 0:0834641c241a 308 writeDebugByte(CMD_BURST_WRITE | HIBYTE(num_bytes));
hudakz 0:0834641c241a 309 writeDebugByte(LOBYTE(num_bytes));
hudakz 0:0834641c241a 310 for (i = 0; i < num_bytes; i++) {
hudakz 0:0834641c241a 311 writeDebugByte(src[i]);
hudakz 0:0834641c241a 312 }
hudakz 0:0834641c241a 313
hudakz 0:0834641c241a 314 // Set DD as input
hudakz 0:0834641c241a 315 dd.input();
hudakz 0:0834641c241a 316 dd.mode(PullUp);
hudakz 0:0834641c241a 317 // Wait for DUP to be ready
hudakz 0:0834641c241a 318 waitDupReady();
hudakz 0:0834641c241a 319 readDebugByte(); // ignore output
hudakz 0:0834641c241a 320 // Set DD as output
hudakz 0:0834641c241a 321 dd.output();
hudakz 0:0834641c241a 322 }
hudakz 0:0834641c241a 323
hudakz 0:0834641c241a 324 /**************************************************************************/
hudakz 0:0834641c241a 325
hudakz 0:0834641c241a 326 /**
hudakz 0:0834641c241a 327 * @brief Issues a CHIP_ERASE command on the debug interface and waits for it
hudakz 0:0834641c241a 328 * to complete.
hudakz 0:0834641c241a 329 * @return None.
hudakz 0:0834641c241a 330 ******************************************************************************/
hudakz 0:0834641c241a 331 void chipErase(void)
hudakz 0:0834641c241a 332 {
hudakz 0:0834641c241a 333 volatile unsigned char status;
hudakz 0:0834641c241a 334 // Send command
hudakz 0:0834641c241a 335 debugCommand(CMD_CHIP_ERASE, 0, 0);
hudakz 0:0834641c241a 336
hudakz 0:0834641c241a 337 // Wait for status bit 7 to go low
hudakz 0:0834641c241a 338 do {
hudakz 0:0834641c241a 339 status = debugCommand(CMD_READ_STATUS, 0, 0);
hudakz 0:0834641c241a 340 } while ((status & STATUS_CHIP_ERASE_BUSY_BM));
hudakz 0:0834641c241a 341 }
hudakz 0:0834641c241a 342
hudakz 0:0834641c241a 343 /**************************************************************************/
hudakz 0:0834641c241a 344
hudakz 0:0834641c241a 345 /**
hudakz 0:0834641c241a 346 * @brief Writes a block of data to the DUP's XDATA space.
hudakz 0:0834641c241a 347 * @param address XDATA start address
hudakz 0:0834641c241a 348 * @param values Pointer to the array of bytes to write
hudakz 0:0834641c241a 349 * @param num_bytes Number of bytes to write
hudakz 0:0834641c241a 350 * @return None.
hudakz 0:0834641c241a 351 ******************************************************************************/
hudakz 0:0834641c241a 352 void writeXdataMemoryBlock(unsigned short address, const unsigned char* values, unsigned short num_bytes)
hudakz 0:0834641c241a 353 {
hudakz 0:0834641c241a 354 unsigned char instr[3];
hudakz 0:0834641c241a 355 unsigned short i;
hudakz 0:0834641c241a 356
hudakz 0:0834641c241a 357 // MOV DPTR, address
hudakz 0:0834641c241a 358 instr[0] = 0x90;
hudakz 0:0834641c241a 359 instr[1] = HIBYTE(address);
hudakz 0:0834641c241a 360 instr[2] = LOBYTE(address);
hudakz 0:0834641c241a 361 debugCommand(CMD_DEBUG_INSTR_3B, instr, 3);
hudakz 0:0834641c241a 362
hudakz 0:0834641c241a 363 for (i = 0; i < num_bytes; i++) {
hudakz 0:0834641c241a 364 // MOV A, values[i]
hudakz 0:0834641c241a 365 instr[0] = 0x74;
hudakz 0:0834641c241a 366 instr[1] = values[i];
hudakz 0:0834641c241a 367 debugCommand(CMD_DEBUG_INSTR_2B, instr, 2);
hudakz 0:0834641c241a 368
hudakz 0:0834641c241a 369 // MOV @DPTR, A
hudakz 0:0834641c241a 370 instr[0] = 0xF0;
hudakz 0:0834641c241a 371 debugCommand(CMD_DEBUG_INSTR_1B, instr, 1);
hudakz 0:0834641c241a 372
hudakz 0:0834641c241a 373 // INC DPTR
hudakz 0:0834641c241a 374 instr[0] = 0xA3;
hudakz 0:0834641c241a 375 debugCommand(CMD_DEBUG_INSTR_1B, instr, 1);
hudakz 0:0834641c241a 376 }
hudakz 0:0834641c241a 377 }
hudakz 0:0834641c241a 378
hudakz 0:0834641c241a 379 /**************************************************************************/
hudakz 0:0834641c241a 380
hudakz 0:0834641c241a 381 /**
hudakz 0:0834641c241a 382 * @brief Writes a byte to a specific address in the DUP's XDATA space.
hudakz 0:0834641c241a 383 * @param address XDATA address
hudakz 0:0834641c241a 384 * @param value Value to write
hudakz 0:0834641c241a 385 * @return None.
hudakz 0:0834641c241a 386 ******************************************************************************/
hudakz 0:0834641c241a 387 void writeXdataMemory(unsigned short address, unsigned char value)
hudakz 0:0834641c241a 388 {
hudakz 0:0834641c241a 389 unsigned char instr[3];
hudakz 0:0834641c241a 390
hudakz 0:0834641c241a 391 // MOV DPTR, address
hudakz 0:0834641c241a 392 instr[0] = 0x90;
hudakz 0:0834641c241a 393 instr[1] = HIBYTE(address);
hudakz 0:0834641c241a 394 instr[2] = LOBYTE(address);
hudakz 0:0834641c241a 395 debugCommand(CMD_DEBUG_INSTR_3B, instr, 3);
hudakz 0:0834641c241a 396
hudakz 0:0834641c241a 397 // MOV A, values[i]
hudakz 0:0834641c241a 398 instr[0] = 0x74;
hudakz 0:0834641c241a 399 instr[1] = value;
hudakz 0:0834641c241a 400 debugCommand(CMD_DEBUG_INSTR_2B, instr, 2);
hudakz 0:0834641c241a 401
hudakz 0:0834641c241a 402 // MOV @DPTR, A
hudakz 0:0834641c241a 403 instr[0] = 0xF0;
hudakz 0:0834641c241a 404 debugCommand(CMD_DEBUG_INSTR_1B, instr, 1);
hudakz 0:0834641c241a 405 }
hudakz 0:0834641c241a 406
hudakz 0:0834641c241a 407 /**************************************************************************/
hudakz 0:0834641c241a 408
hudakz 0:0834641c241a 409 /**
hudakz 0:0834641c241a 410 * @brief Read a byte from a specific address in the DUP's XDATA space.
hudakz 0:0834641c241a 411 * @param address XDATA address
hudakz 0:0834641c241a 412 * @return Value read from XDATA
hudakz 0:0834641c241a 413 ******************************************************************************/
hudakz 0:0834641c241a 414 unsigned char readXdataMemory(unsigned short address)
hudakz 0:0834641c241a 415 {
hudakz 0:0834641c241a 416 unsigned char instr[3];
hudakz 0:0834641c241a 417
hudakz 0:0834641c241a 418 // MOV DPTR, address
hudakz 0:0834641c241a 419 instr[0] = 0x90;
hudakz 0:0834641c241a 420 instr[1] = HIBYTE(address);
hudakz 0:0834641c241a 421 instr[2] = LOBYTE(address);
hudakz 0:0834641c241a 422 debugCommand(CMD_DEBUG_INSTR_3B, instr, 3);
hudakz 0:0834641c241a 423
hudakz 0:0834641c241a 424 // MOVX A, @DPTR
hudakz 0:0834641c241a 425 instr[0] = 0xE0;
hudakz 0:0834641c241a 426 return debugCommand(CMD_DEBUG_INSTR_1B, instr, 1);
hudakz 0:0834641c241a 427 }
hudakz 0:0834641c241a 428
hudakz 0:0834641c241a 429 /**************************************************************************/
hudakz 0:0834641c241a 430
hudakz 0:0834641c241a 431 /**
hudakz 0:0834641c241a 432 * @brief Reads 1-32767 bytes from DUP's flash to a given buffer on the
hudakz 0:0834641c241a 433 * programmer.
hudakz 0:0834641c241a 434 * @param bank Flash bank to read from [0-7]
hudakz 0:0834641c241a 435 * @param address Flash memory start address [0x0000 - 0x7FFF]
hudakz 0:0834641c241a 436 * @param values Pointer to destination buffer.
hudakz 0:0834641c241a 437 * @return None.
hudakz 0:0834641c241a 438 ******************************************************************************/
hudakz 0:0834641c241a 439 void readFlashMemoryBlock
hudakz 0:0834641c241a 440 (
hudakz 0:0834641c241a 441 unsigned char bank,
hudakz 0:0834641c241a 442 unsigned short flash_addr,
hudakz 0:0834641c241a 443 unsigned short num_bytes,
hudakz 0:0834641c241a 444 unsigned char* values
hudakz 0:0834641c241a 445 )
hudakz 0:0834641c241a 446 {
hudakz 0:0834641c241a 447 unsigned char instr[3];
hudakz 0:0834641c241a 448 unsigned short i;
hudakz 0:0834641c241a 449 unsigned short xdata_addr = (0x8000 + flash_addr);
hudakz 0:0834641c241a 450
hudakz 0:0834641c241a 451 // 1. Map flash memory bank to XDATA address 0x8000-0xFFFF
hudakz 0:0834641c241a 452 writeXdataMemory(DUP_MEMCTR, bank);
hudakz 0:0834641c241a 453
hudakz 0:0834641c241a 454 // 2. Move data pointer to XDATA address (MOV DPTR, xdata_addr)
hudakz 0:0834641c241a 455 instr[0] = 0x90;
hudakz 0:0834641c241a 456 instr[1] = HIBYTE(xdata_addr);
hudakz 0:0834641c241a 457 instr[2] = LOBYTE(xdata_addr);
hudakz 0:0834641c241a 458 debugCommand(CMD_DEBUG_INSTR_3B, instr, 3);
hudakz 0:0834641c241a 459
hudakz 0:0834641c241a 460 for (i = 0; i < num_bytes; i++) {
hudakz 0:0834641c241a 461 // 3. Move value pointed to by DPTR to accumulator (MOVX A, @DPTR)
hudakz 0:0834641c241a 462 instr[0] = 0xE0;
hudakz 0:0834641c241a 463 values[i] = debugCommand(CMD_DEBUG_INSTR_1B, instr, 1);
hudakz 0:0834641c241a 464
hudakz 0:0834641c241a 465 // 4. Increment data pointer (INC DPTR)
hudakz 0:0834641c241a 466 instr[0] = 0xA3;
hudakz 0:0834641c241a 467 debugCommand(CMD_DEBUG_INSTR_1B, instr, 1);
hudakz 0:0834641c241a 468 }
hudakz 0:0834641c241a 469 }
hudakz 0:0834641c241a 470
hudakz 0:0834641c241a 471 /**************************************************************************/
hudakz 0:0834641c241a 472
hudakz 0:0834641c241a 473 /**
hudakz 0:0834641c241a 474 * @brief Writes 4-2048 bytes to DUP's flash memory. Parameter \c num_bytes
hudakz 0:0834641c241a 475 * must be a multiple of 4.
hudakz 0:0834641c241a 476 * @param src Pointer to programmer's source buffer (in XDATA space)
hudakz 0:0834641c241a 477 * @param start_addr FLASH memory start address [0x0000 - 0x7FFF]
hudakz 0:0834641c241a 478 * @param num_bytes Number of bytes to transfer [4-1024]
hudakz 0:0834641c241a 479 * @return None.
hudakz 0:0834641c241a 480 ******************************************************************************/
hudakz 0:0834641c241a 481 void writeFlashMemoryBlock(unsigned char* src, unsigned long start_addr, unsigned short num_bytes)
hudakz 0:0834641c241a 482 {
hudakz 0:0834641c241a 483 // 1. Write the 2 DMA descriptors to RAM
hudakz 0:0834641c241a 484 writeXdataMemoryBlock(ADDR_DMA_DESC_0, dmaDesc0, 8);
hudakz 0:0834641c241a 485 writeXdataMemoryBlock(ADDR_DMA_DESC_1, dmaDesc1, 8);
hudakz 0:0834641c241a 486
hudakz 0:0834641c241a 487 // 2. Update LEN value in DUP's DMA descriptors
hudakz 0:0834641c241a 488 unsigned char len[2] = { HIBYTE(num_bytes), LOBYTE(num_bytes) };
hudakz 0:0834641c241a 489 writeXdataMemoryBlock((ADDR_DMA_DESC_0 + 4), len, 2); // LEN, DBG => ram
hudakz 0:0834641c241a 490 writeXdataMemoryBlock((ADDR_DMA_DESC_1 + 4), len, 2); // LEN, ram => flash
hudakz 0:0834641c241a 491 // 3. Set DMA controller pointer to the DMA descriptors
hudakz 0:0834641c241a 492 writeXdataMemory(DUP_DMA0CFGH, HIBYTE(ADDR_DMA_DESC_0));
hudakz 0:0834641c241a 493 writeXdataMemory(DUP_DMA0CFGL, LOBYTE(ADDR_DMA_DESC_0));
hudakz 0:0834641c241a 494 writeXdataMemory(DUP_DMA1CFGH, HIBYTE(ADDR_DMA_DESC_1));
hudakz 0:0834641c241a 495 writeXdataMemory(DUP_DMA1CFGL, LOBYTE(ADDR_DMA_DESC_1));
hudakz 0:0834641c241a 496
hudakz 0:0834641c241a 497 // 4. Set Flash controller start address (wants 16MSb of 18 bit address)
hudakz 0:0834641c241a 498 writeXdataMemory(DUP_FADDRH, HIBYTE((start_addr))); //>>2) ));
hudakz 0:0834641c241a 499 writeXdataMemory(DUP_FADDRL, LOBYTE((start_addr))); //>>2) ));
hudakz 0:0834641c241a 500 // 5. Arm DBG=>buffer DMA channel and start burst write
hudakz 0:0834641c241a 501 writeXdataMemory(DUP_DMAARM, CH_DBG_TO_BUF0);
hudakz 0:0834641c241a 502 burstWriteBlock(src, num_bytes);
hudakz 0:0834641c241a 503
hudakz 0:0834641c241a 504 // 6. Start programming: buffer to flash
hudakz 0:0834641c241a 505 writeXdataMemory(DUP_DMAARM, CH_BUF0_TO_FLASH);
hudakz 0:0834641c241a 506 writeXdataMemory(DUP_FCTL, 0x0A); //0x06
hudakz 0:0834641c241a 507 // 7. Wait until flash controller is done
hudakz 0:0834641c241a 508 while (readXdataMemory(DUP_FCTL) & 0x80);
hudakz 0:0834641c241a 509 }
hudakz 0:0834641c241a 510
hudakz 0:0834641c241a 511 /**
hudakz 0:0834641c241a 512 * @brief
hudakz 0:0834641c241a 513 * @note
hudakz 0:0834641c241a 514 * @param
hudakz 0:0834641c241a 515 * @retval
hudakz 0:0834641c241a 516 */
hudakz 0:0834641c241a 517 void runDUP(void)
hudakz 0:0834641c241a 518 {
hudakz 0:0834641c241a 519 volatile unsigned char i;
hudakz 0:0834641c241a 520
hudakz 0:0834641c241a 521 // Send two flanks on DC while keeping RESET_N low
hudakz 0:0834641c241a 522 // All low (incl. RESET_N)
hudakz 0:0834641c241a 523 dd = 0;
hudakz 0:0834641c241a 524 dc = 0;
hudakz 0:0834641c241a 525 reset = 0;
hudakz 0:0834641c241a 526 wait_ms(10); // Wait
hudakz 0:0834641c241a 527 reset = 1;
hudakz 0:0834641c241a 528 wait_ms(10); // Wait
hudakz 0:0834641c241a 529 }
hudakz 0:0834641c241a 530
hudakz 0:0834641c241a 531 /**
hudakz 0:0834641c241a 532 * @brief
hudakz 0:0834641c241a 533 * @note
hudakz 0:0834641c241a 534 * @param
hudakz 0:0834641c241a 535 * @retval
hudakz 0:0834641c241a 536 */
hudakz 0:0834641c241a 537 void programmerInit(void)
hudakz 0:0834641c241a 538 {
hudakz 0:0834641c241a 539 dd.output();
hudakz 0:0834641c241a 540 dd = 0;
hudakz 0:0834641c241a 541 dc = 0;
hudakz 0:0834641c241a 542 reset = 1;
hudakz 0:0834641c241a 543 led = 0;
hudakz 0:0834641c241a 544 }
hudakz 0:0834641c241a 545
hudakz 0:0834641c241a 546 /**
hudakz 0:0834641c241a 547 * @brief
hudakz 0:0834641c241a 548 * @note
hudakz 0:0834641c241a 549 * @param
hudakz 0:0834641c241a 550 * @retval
hudakz 0:0834641c241a 551 */
hudakz 0:0834641c241a 552 int main()
hudakz 0:0834641c241a 553 {
hudakz 0:0834641c241a 554 programmerInit();
hudakz 0:0834641c241a 555 serial.baud(115200);
hudakz 0:0834641c241a 556 // If using Leonado as programmer,
hudakz 0:0834641c241a 557 // it should add below code,otherwise,comment it.
hudakz 0:0834641c241a 558 //while (!Serial);
hudakz 0:0834641c241a 559 while (true) {
hudakz 0:0834641c241a 560 unsigned char chipId = 0;
hudakz 0:0834641c241a 561 unsigned char debugConfig = 0;
hudakz 0:0834641c241a 562 unsigned char goOn = 0;
hudakz 0:0834641c241a 563 unsigned char verify = 0;
hudakz 0:0834641c241a 564
hudakz 0:0834641c241a 565 while (!goOn) {
hudakz 0:0834641c241a 566 // Wait for starting
hudakz 0:0834641c241a 567 if (serial.readable()) {
hudakz 0:0834641c241a 568 if (serial.getc() == SBEGIN) {
hudakz 0:0834641c241a 569 verify = serial.getc();
hudakz 0:0834641c241a 570 goOn = 1;
hudakz 0:0834641c241a 571 }
hudakz 0:0834641c241a 572 else {
hudakz 0:0834641c241a 573 serial.getc(); // Clear RX buffer
hudakz 0:0834641c241a 574 }
hudakz 0:0834641c241a 575 }
hudakz 0:0834641c241a 576 }
hudakz 0:0834641c241a 577
hudakz 0:0834641c241a 578 debugInit();
hudakz 0:0834641c241a 579 chipId = readChipId();
hudakz 0:0834641c241a 580 if (chipId == 0) {
hudakz 0:0834641c241a 581 serial.putc(ERRO);
hudakz 0:0834641c241a 582 return 1; // No chip detected, run loop again.
hudakz 0:0834641c241a 583 }
hudakz 0:0834641c241a 584
hudakz 0:0834641c241a 585 runDUP();
hudakz 0:0834641c241a 586 debugInit();
hudakz 0:0834641c241a 587
hudakz 0:0834641c241a 588 chipErase();
hudakz 0:0834641c241a 589 runDUP();
hudakz 0:0834641c241a 590 debugInit();
hudakz 0:0834641c241a 591
hudakz 0:0834641c241a 592 // Switch DUP to external crystal osc. (XOSC) and wait for it to be stable.
hudakz 0:0834641c241a 593 // This is recommended if XOSC is available during programming. If
hudakz 0:0834641c241a 594 // XOSC is not available, comment out these two lines.
hudakz 0:0834641c241a 595 //writeXdataMemory(DUP_CLKCONCMD, 0x80);
hudakz 0:0834641c241a 596 //while (readXdataMemory(DUP_CLKCONSTA) != 0x80);
hudakz 0:0834641c241a 597 //0x80)
hudakz 0:0834641c241a 598 // Enable DMA (Disable DMA_PAUSE bit in debug configuration)
hudakz 0:0834641c241a 599 debugConfig = 0x22;
hudakz 0:0834641c241a 600 debugCommand(CMD_WR_CONFIG, &debugConfig, 1);
hudakz 0:0834641c241a 601
hudakz 0:0834641c241a 602 // Program data (start address must be word aligned [32 bit])
hudakz 0:0834641c241a 603 serial.putc(SRSP); // Request data blocks
hudakz 0:0834641c241a 604 led = 1;
hudakz 0:0834641c241a 605
hudakz 0:0834641c241a 606 unsigned char done = 0;
hudakz 0:0834641c241a 607 unsigned char state = WAITING;
hudakz 0:0834641c241a 608 unsigned char rxBuf[514];
hudakz 0:0834641c241a 609 unsigned int bufIndex = 0;
hudakz 0:0834641c241a 610 unsigned int addr = 0x0000;
hudakz 0:0834641c241a 611 while (!done) {
hudakz 0:0834641c241a 612 while (serial.readable()) {
hudakz 0:0834641c241a 613 unsigned char ch;
hudakz 0:0834641c241a 614 ch = serial.getc();
hudakz 0:0834641c241a 615 switch (state) {
hudakz 0:0834641c241a 616 // Bootloader is waiting for a new block, each block begin with a flag byte
hudakz 0:0834641c241a 617 case WAITING:
hudakz 0:0834641c241a 618 {
hudakz 0:0834641c241a 619 if (SDATA == ch) {
hudakz 0:0834641c241a 620 // Incoming bytes are data
hudakz 0:0834641c241a 621 state = RECEIVING;
hudakz 0:0834641c241a 622 }
hudakz 0:0834641c241a 623 else
hudakz 0:0834641c241a 624 if (SEND == ch) {
hudakz 0:0834641c241a 625 // End receiving firmware
hudakz 0:0834641c241a 626 done = 1; // Exit while(1) in main function
hudakz 0:0834641c241a 627 }
hudakz 0:0834641c241a 628 break;
hudakz 0:0834641c241a 629 }
hudakz 0:0834641c241a 630
hudakz 0:0834641c241a 631 // Bootloader is receiving block data
hudakz 0:0834641c241a 632 case RECEIVING:
hudakz 0:0834641c241a 633 {
hudakz 0:0834641c241a 634 rxBuf[bufIndex] = ch;
hudakz 0:0834641c241a 635 bufIndex++;
hudakz 0:0834641c241a 636 if (bufIndex == 514) {
hudakz 0:0834641c241a 637 // If received one block, write it to flash
hudakz 0:0834641c241a 638 bufIndex = 0;
hudakz 0:0834641c241a 639
hudakz 0:0834641c241a 640 uint16_t checkSum = 0x0000;
hudakz 0:0834641c241a 641 for (unsigned int i = 0; i < 512; i++) {
hudakz 0:0834641c241a 642 checkSum += rxBuf[i];
hudakz 0:0834641c241a 643 }
hudakz 0:0834641c241a 644
hudakz 0:0834641c241a 645 uint16_t checkSum_t = rxBuf[512] << 8 | rxBuf[513];
hudakz 0:0834641c241a 646 if (checkSum_t != checkSum) {
hudakz 0:0834641c241a 647 state = WAITING;
hudakz 0:0834641c241a 648 serial.putc(ERRO);
hudakz 0:0834641c241a 649 chipErase();
hudakz 0:0834641c241a 650 return 1;
hudakz 0:0834641c241a 651 }
hudakz 0:0834641c241a 652
hudakz 0:0834641c241a 653 writeFlashMemoryBlock(rxBuf, addr, 512); // src, address, count
hudakz 0:0834641c241a 654 if (verify) {
hudakz 0:0834641c241a 655 unsigned char bank = addr / (512 * 16);
hudakz 0:0834641c241a 656 unsigned int offset = (addr % (512 * 16)) * 4;
hudakz 0:0834641c241a 657 unsigned char readData[512];
hudakz 0:0834641c241a 658 readFlashMemoryBlock(bank, offset, 512, readData); // Bank, address, count, dest.
hudakz 0:0834641c241a 659 for (unsigned int i = 0; i < 512; i++) {
hudakz 0:0834641c241a 660 if (readData[i] != rxBuf[i]) {
hudakz 0:0834641c241a 661 // Fail
hudakz 0:0834641c241a 662 state = WAITING;
hudakz 0:0834641c241a 663 serial.putc(ERRO);
hudakz 0:0834641c241a 664 chipErase();
hudakz 0:0834641c241a 665 return 1;
hudakz 0:0834641c241a 666 }
hudakz 0:0834641c241a 667 }
hudakz 0:0834641c241a 668 }
hudakz 0:0834641c241a 669
hudakz 0:0834641c241a 670 addr += (unsigned int)128;
hudakz 0:0834641c241a 671 state = WAITING;
hudakz 0:0834641c241a 672 serial.putc(SRSP);
hudakz 0:0834641c241a 673 }
hudakz 0:0834641c241a 674 break;
hudakz 0:0834641c241a 675 }
hudakz 0:0834641c241a 676
hudakz 0:0834641c241a 677 default:
hudakz 0:0834641c241a 678 break;
hudakz 0:0834641c241a 679 }
hudakz 0:0834641c241a 680 }
hudakz 0:0834641c241a 681 }
hudakz 0:0834641c241a 682
hudakz 0:0834641c241a 683 led = 0;
hudakz 0:0834641c241a 684 runDUP();
hudakz 0:0834641c241a 685 }
hudakz 0:0834641c241a 686 }