Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Revision:
1:d5452e398b76
Child:
2:bf3a2b29259a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bdmcpu32.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,1300 @@
+/*******************************************************************************
+
+bdmcpu32.cpp
+(c) 2010 by Sophie Dexter
+
+Generic BDM functions for Just4Trionic by Just4pLeisure
+
+A derivative work based on:
+//-----------------------------------------------------------------------------
+//    CAN/BDM adapter firmware
+//    (C) Janis Silins, 2010
+//    $id$
+//-----------------------------------------------------------------------------
+
+********************************************************************************
+
+WARNING: Use at your own risk, sadly this software comes with no guarantees.
+This software is provided 'free' and in good faith, but the author does not
+accept liability for any damage arising from its use.
+
+*******************************************************************************/
+
+#include "bdmcpu32.h"
+
+// constants
+#define MCU_SETTLE_TIME     10        ///< delay to let MCU switch modes, ms
+#define CMD_BIT_COUNT       17        ///< command size, bits
+
+// BDM commands
+#define BDM_NOP             0x0000    ///< no-op
+#define BDM_GO              0x0c00    ///< resume execution
+#define BDM_WRITE           0x1800    ///< write memory
+#define BDM_READ            0x1900    ///< read memory 
+#define BDM_WSREG           0x2480    ///< write system register
+#define BDM_RSREG           0x2580    ///< read system register
+#define BDM_RDREG           0x2180    ///< read A/D register
+#define BDM_WRREG           0x2080    ///< write A/D register
+#define BDM_DUMP            0x1d00    ///< dump memory
+#define BDM_FILL            0x1c00    ///< fill memory
+#define BDM_CALL            0x0800    ///< function call
+#define BDM_RST             0x0400    ///< reset
+
+// system registers
+#define SREG_RPC            0x0
+#define SREG_PCC            0x1
+#define SREG_SR             0xb
+#define SREG_USP            0xc
+#define SREG_SSP            0xd
+#define SREG_SFC            0xe
+#define SREG_DFC            0xf
+#define SREG_ATEMP          0x8
+#define SREG_FAR            0x9
+#define SREG_VBR            0xa
+
+// BDM responses
+#define BDM_CMDCMPLTE       0x0000ffff    ///< command complete
+#define BDM_NOTREADY        0x00010000    ///< response not ready
+#define BDM_BERR            0x00010001    ///< error
+#define BDM_ILLEGAL         0x0001ffff    ///< illegal command
+
+// BDM data sizes
+#define BDM_BYTESIZE        0x00        ///< byte
+#define BDM_WORDSIZE        0x40        ///< word (2 bytes)
+#define BDM_LONGSIZE        0x80        ///< long word (4 bytes)
+
+// static variables
+static uint32_t bdm_response;        ///< result of BDM read/write operation
+
+// private functions
+bool bdm_read(uint32_t* result, uint16_t cmd, const uint32_t* addr);
+//bool bdm_read_overlap(uint32_t* result, uint16_t cmd, const uint32_t* addr, uint16_t next_cmd);
+//bool bdm_read_continue(uint32_t* result, const uint32_t* addr, uint16_t next_cmd);
+bool bdm_write(const uint32_t* addr, uint16_t cmd, const uint32_t* value);
+//bool bdm_write_overlap(const uint32_t* addr, uint16_t cmd, const uint32_t* value, uint16_t next_cmd);
+void bdm_clk(uint16_t value, uint8_t num_bits);
+void bdm_clear();
+
+//-----------------------------------------------------------------------------
+/**
+    Stops target MCU and puts into background debug mode (BDM).
+
+    @return                        status flag
+*/
+uint8_t stop_chip() {
+    // not connected
+    if (!IS_CONNECTED) {
+        return TERM_ERR;
+    }
+
+    // pull BKPT low to enter background mode (the pin must remain in output mode,
+    // otherwise the target will pull it high and we'll lose the first DSO bit)
+    PIN_BKPT.write(0);
+    // set BPKT pin as output
+    PIN_BKPT.output();
+
+    // wait for target MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+
+    // check if succeeded
+    if (!IN_BDM) {
+        // set BKPT back as input and fail
+        PIN_BKPT.input();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Forces hardware reset on target MCU and lets it run.
+
+    @return                        status flag
+*/
+uint8_t reset_chip() {
+    // not connected
+    if (!IS_CONNECTED) {
+        return TERM_ERR;
+    }
+
+    // BKPT pin as input
+    PIN_BKPT.input();
+    // push RESET low
+    PIN_RESET.write(0);
+    // RESET pins as output
+    PIN_RESET.output();
+    // wait for MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+    // rising edge on RESET line
+    PIN_RESET.write(1);
+    // wait for MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+
+    // set RESET as an input again
+    PIN_RESET.input();
+
+    // check if succeeded
+    return IS_RUNNING ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Starts target MCU from the specified address. If address is 0, execution
+    begins at the current address in program counter.
+
+    @param            addr        start address
+
+    @return                        status flag
+*/
+uint8_t run_chip(const uint32_t* addr) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // set program counter
+    if ((*addr > 0) && sysreg_write(SREG_RPC, addr) != TERM_OK) {
+        return TERM_ERR;
+    }
+    // resume MCU
+    bdm_clk(BDM_GO, CMD_BIT_COUNT);
+
+    // set BKPT back as input
+    PIN_BKPT.input();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Resets target MCU and stops execution on first instruction fetch.
+
+    @return                        status flag
+*/
+uint8_t restart_chip() {
+    // not connected
+    if (!IS_CONNECTED) {
+        return TERM_ERR;
+    }
+
+    // pull BKPT low to enter background mode (the pin must remain an output,
+    // otherwise the target will pull it high and we'll lose the first DSO bit)
+    PIN_BKPT.write(0);
+    // push RESET low
+    PIN_RESET.write(0);
+    // RESET, BKPT pins as outputs
+    PIN_BKPT.output();
+    PIN_RESET.output();
+    // wait for target MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+    // rising edge on RESET line
+    PIN_RESET.write(1);
+    // wait for target MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+    // set RESET back as an input
+    PIN_RESET.input();
+
+    // check if succeeded
+    if (!IN_BDM) {
+        // set BKPT back as input and fail
+        PIN_BKPT.input();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Sends GO command word to target MCU, then triggers breakpoint on first
+    instruction fetch.
+
+    @return                        status flag
+*/
+uint8_t step_chip() {
+    // not connected
+    if (!IS_CONNECTED) {
+        return TERM_ERR;
+    }
+
+    // resume MCU
+    bdm_clk(BDM_GO, CMD_BIT_COUNT);
+
+    // pull BKPT low to enter background mode (the pin must remain an output,
+    // otherwise the target pulls it high and we lose the first DSO bit)
+    PIN_BKPT.write(0);
+    // set BPKT pin as output
+    PIN_BKPT.output();
+
+    // wait for target MCU to settle
+//    delay_ms(MCU_SETTLE_TIME);
+    wait_ms(MCU_SETTLE_TIME);
+
+    // check if succeeded
+    if (!IN_BDM) {
+        // set BKPT back as input and fail
+        PIN_BKPT.input();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Pulls BKPT pin low.
+*/
+uint8_t bkpt_low() {
+    PIN_BKPT.write(0);
+    PIN_BKPT.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Pulls BKPT pin high.
+*/
+uint8_t bkpt_high() {
+    PIN_BKPT.write(1);
+    PIN_BKPT.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Pulls RESET pin low.
+*/
+uint8_t reset_low() {
+    PIN_RESET.write(0);
+    PIN_RESET.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Pulls RESET pin high.
+*/
+uint8_t reset_high() {
+    PIN_RESET.write(1);
+    PIN_RESET.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Returns byte from the specified memory location; MCU must be in
+    background mode.
+
+    @param        result            value (out)
+    @param        addr            source address
+
+    @return                        status flag
+*/
+uint8_t memread_byte(uint8_t* result, const uint32_t* addr) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // read byte
+    if (!bdm_read((uint32_t*)result, BDM_READ, addr)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Returns word (2 bytes) from the specified memory location. Address must be
+    word-aligned and MCU must be in background mode.
+
+    @param        result            value (out)
+    @param        addr            source address
+
+    @return                        status flag
+*/
+uint8_t memread_word(uint16_t* result, const uint32_t* addr) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // read word
+    if (!bdm_read((uint32_t*)result, BDM_READ + BDM_WORDSIZE, addr)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Returns long word (4 bytes) from the specified memory location. Address
+    must be word-aligned and target MCU must be in background mode.
+
+    @param            result            value
+    @param            addr            source address
+
+    @return                            status flag
+*/
+uint8_t memread_long(uint32_t* result, const uint32_t* addr) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    //  read long word
+    if (!bdm_read(result, BDM_READ + BDM_LONGSIZE, addr)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Dumps byte from the specified memory location; MCU must be in background
+    mode. Any memread_*() function must be called beforehand to set the
+    initial address.
+
+    @param        value            result (out)
+
+    @return                        status flag
+*/
+uint8_t memdump_byte(uint8_t* result) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // dump byte
+    if (!bdm_read((uint32_t*)result, BDM_DUMP, NULL)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    dumps word from the specified memory location; MCU must be in background
+    mode. Any memread_*() function must be called beforehand to set the
+    initial address.
+
+    @param        value            result (out)
+
+    @return                        status flag
+*/
+uint8_t memdump_word(uint16_t* result) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // dump word
+    if (!bdm_read((uint32_t*)result, BDM_DUMP + BDM_WORDSIZE, NULL)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Dumps long word  from the specified memory location; MCU must be in
+    background mode. Any memread_*() function must be called beforehand to set
+    the initial address.
+
+    @param        value            result (out)
+
+    @return                        status flag
+*/
+uint8_t memdump_long(uint32_t* result) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // dump long word
+    if (!bdm_read(result, BDM_DUMP + BDM_LONGSIZE, NULL)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes byte to the specified memory location; MCU must be in background
+    mode.
+
+    @param        addr            destination address
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memwrite_byte(const uint32_t* addr, uint8_t value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write byte
+    if (!bdm_write(addr, BDM_WRITE, (uint32_t*)&value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes word to the specified memory location. Address must be word-aligned
+    and MCU must be in background mode.
+
+    @param        addr            memory address
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memwrite_word(const uint32_t* addr, uint16_t value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write word
+    if (!bdm_write(addr, BDM_WRITE + BDM_WORDSIZE, (uint32_t*)&value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes long word to the specified memory location. Address must be
+    word-aligned and target MCU must be in background mode.
+
+    @param        addr            memory address
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memwrite_long(const uint32_t* addr, const uint32_t* value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write long word
+    if (!bdm_write(addr, BDM_WRITE + BDM_LONGSIZE, value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes byte to the current memory location; MCU must be in background
+    mode. Any memwrite_*() function must be called beforehand to set the
+    current address.
+
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memfill_byte(uint8_t value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // fill byte
+    if (!bdm_write(NULL, BDM_FILL, (uint32_t*)&value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes word to the specified memory location; MCU must be in background
+    mode. Any memwrite_*() function must be called beforehand to set the
+    initial address.
+
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memfill_word(uint16_t value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // fill word
+    if (!IN_BDM || !bdm_write(NULL, BDM_FILL + BDM_WORDSIZE, (uint32_t*)&value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes long word to the specified memory location; MCU must be in background
+    mode. Any memwrite_*() function must be called beforehand to set the
+    initial address.
+
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memfill_long(const uint32_t* value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // fill long word
+    if (!bdm_write(NULL, BDM_FILL + BDM_LONGSIZE, value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a read byte command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memread_byte_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    if (!bdm_command(BDM_READ + BDM_BYTESIZE)) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a read word command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memread_word_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    bdm_clk(BDM_READ + BDM_WORDSIZE, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a read long command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memread_long_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    bdm_clk(BDM_READ + BDM_LONGSIZE, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+//-----------------------------------------------------------------------------
+/**
+    Issues a write byte command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memwrite_byte_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+    
+    // write command code
+    if (!bdm_command(BDM_WRITE + BDM_BYTESIZE)) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a write word command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memwrite_word_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    bdm_clk(BDM_WRITE + BDM_WORDSIZE, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a write long command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memwrite_long_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    bdm_clk(BDM_WRITE + BDM_LONGSIZE, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a byte from the MCU (follows a previously sent read or dump word cmd)
+    Sends a READ_BYTE command so that commands overlap
+
+    @param        result        read result (out)
+                  addr          address (optional)
+
+    @return                     status flag
+*/
+uint8_t memread_read_byte(uint8_t* result, const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // receive the response byte
+    return (bdm_get ((uint32_t*)result, BDM_BYTESIZE, BDM_READ + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a byte from the MCU (follows a previously sent read or dump word cmd)
+    Sends a WRITE_BYTE command so that commands overlap
+
+    @param        result        read result (out)
+                  addr          address (optional)
+
+    @return                     status flag
+*/
+uint8_t memread_write_byte(uint8_t* result, const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // receive the response byte
+    return (bdm_get((uint32_t*)result, BDM_BYTESIZE, BDM_WRITE + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a byte from the MCU (follows a previously sent read or dump word cmd)
+    Sends a BDM_NOP command to end a sequence of overlapping commands
+
+    @param        result        read result (out)
+                  addr          address (optional)
+
+    @return                     status flag
+*/
+uint8_t memread_nop_byte(uint8_t* result, const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // receive the response byte
+    return (bdm_get((uint32_t*)result, BDM_BYTESIZE, BDM_NOP)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a byte to the MCU (follows a previously sent write or fill word cmd)
+    Sends a WRITE_BYTE command so that commands overlap
+
+    @param        addr          address (optional)
+                  value         value to write
+
+    @return                     status flag
+*/
+uint8_t memwrite_write_byte(const uint32_t* addr, uint8_t value) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // write the value
+    if (!bdm_put((uint32_t*)&value, BDM_BYTESIZE)) return TERM_ERR;
+    // wait until MCU responds
+    return (bdm_ready(BDM_WRITE + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a byte to the MCU (follows a previously sent write or fill word cmd)
+    Sends a READ_BYTE command so that commands overlap
+
+    @param        addr          address (optional)
+                  value         value to write
+
+    @return                     status flag
+*/
+uint8_t memwrite_read_byte(const uint32_t* addr, uint8_t value) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // write the value
+    if (!bdm_put((uint32_t*)&value, BDM_BYTESIZE)) return TERM_ERR;
+    // wait until MCU responds
+    return (bdm_ready(BDM_READ + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a byte to the MCU (follows a previously sent write or fill word cmd)
+    Sends a BDM_NOP command to end a sequence of overlapping commands
+
+    @param        addr          address (optional)
+                  value         value to write
+
+    @return                     status flag
+*/
+uint8_t memwrite_nop_byte(const uint32_t* addr, uint8_t value) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // write the value
+    if (!bdm_put((uint32_t*)&value, BDM_BYTESIZE)) return TERM_ERR;
+    // wait until MCU responds
+    return (bdm_ready(BDM_NOP)) ? TERM_OK : TERM_ERR;
+}
+
+
+//-----------------------------------------------------------------------------
+/**
+    Writes 2 words to the same address
+    The BDM commands are overlapped to make things a bit faster
+    A BDM_NOP command is then sent to end the sequence of overlapping commands
+    
+    @param        addr          address
+                  value1, 2     values to write
+
+    @return                     status flag
+*/
+uint8_t memwrite_word_write_word(const uint32_t* addr, const uint16_t value1, const uint16_t value2) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    if (!bdm_command(BDM_WRITE + BDM_WORDSIZE)) return TERM_ERR;
+    // write the address
+    if (!bdm_address(addr)) return TERM_ERR;
+    // write the first value
+    if (!bdm_put((uint32_t*)&value1, BDM_WORDSIZE)) return TERM_ERR;
+    // wait until MCU responds and overlap the next write command
+    if (!bdm_ready(BDM_WRITE + BDM_WORDSIZE)) return TERM_ERR;
+    // write the address (same address for second word)
+    if (!bdm_address(addr)) return TERM_ERR;
+    // write the second value
+    if (!bdm_put((uint32_t*)&value2, BDM_WORDSIZE)) return TERM_ERR;
+    // wait until MCU responds
+    return (bdm_ready(BDM_NOP)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a word then reads back a result from the same address
+    The BDM commands are overlapped to make things a bit faster
+    A BDM_NOP command is then sent to end the sequence of overlapping commands
+
+    @param        result        read result (out)
+                  addr          address
+                  value         value to write
+
+    @return                     status flag
+*/
+
+uint8_t memwrite_word_read_word(uint16_t* result, const uint32_t* addr, const uint16_t value) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    if (!bdm_command(BDM_WRITE + BDM_WORDSIZE)) return TERM_ERR;
+    // write the address
+    if (!bdm_address(addr)) return TERM_ERR;
+    // write the value
+    if (!bdm_put((uint32_t*)&value, BDM_WORDSIZE)) return TERM_ERR;
+    // wait until MCU responds and overlap the next read command
+    if (!bdm_ready(BDM_READ + BDM_WORDSIZE)) return TERM_ERR;
+    // write the address (same address for reading the result)
+    if (!bdm_address(addr)) return TERM_ERR;
+    // receive the response word
+    return (bdm_get((uint32_t*)result, BDM_WORDSIZE, BDM_NOP)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a word from the MCU (follows a previously sent read or dump word cmd)
+    Sends a DUMP_WORD command so that dump commands overlap
+
+    @param        result        read result (out)
+
+    @return                     status flag
+*/
+uint8_t memget_word(uint16_t* result) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // receive the response word
+    return (bdm_get((uint32_t*)result, BDM_WORDSIZE, BDM_DUMP + BDM_WORDSIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a long from the MCU (follows a previously sent read or dump long cmd)
+    Sends a DUMP_LONG command so that dump commands overlap
+
+    @param        result        read result (out)
+
+    @return                     status flag
+*/
+uint8_t memget_long(uint32_t* result) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // receive the response words
+    return (bdm_get(result, BDM_LONGSIZE, BDM_DUMP + BDM_LONGSIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Reads value from system register.
+
+    @param        result            register value (out)
+    @param        reg                register
+
+    @return                        status flag
+*/
+uint8_t sysreg_read(uint32_t* result, uint8_t reg) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // read register
+    if (!bdm_read(result, BDM_RSREG + reg, NULL)) {
+        // clear the interface and fail
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes value to system register.
+
+    @param        reg                register
+    @param        value            register value
+
+    @return                        status flag
+*/
+uint8_t sysreg_write(uint8_t reg, const uint32_t* value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write register
+    if (!bdm_write(NULL, BDM_WSREG + reg, value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Reads value from A/D register.
+
+    @param        result            register value (out)
+    @param        reg                register
+
+    @return                        status flag
+*/
+uint8_t adreg_read(uint32_t* result, uint8_t reg) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // read register
+    if (!bdm_read(result, BDM_RDREG + reg, NULL)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes value to A/D register.
+
+    @param        reg                register
+    @param        value            register value
+
+    @return                        status flag
+*/
+uint8_t adreg_write(uint8_t reg, const uint32_t* value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write register
+    if (!bdm_write(NULL, BDM_WRREG + reg, value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a read command to MCU.
+
+    @param        result        read result (out)
+    @param        cmd            command sequence
+    @param        addr        address (optional)
+
+    @return                    succ / fail
+*/
+bool bdm_read(uint32_t* result, uint16_t cmd, const uint32_t* addr) {
+    *result = 0;
+
+    // write command code
+    bdm_clk(cmd, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) {
+        return false;
+    }
+
+    // write the optional address
+    if (addr) {
+        // first word
+        bdm_clk((uint16_t)(*addr >> 16), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+        // second word
+        bdm_clk((uint16_t)(*addr), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+    }
+
+    // receive response words
+    uint8_t wait_cnt;
+    for (uint8_t curr_word = 0; curr_word < ((cmd & BDM_LONGSIZE) ? 2 : 1);
+            ++curr_word) {
+        // wait while MCU prepares the response
+        wait_cnt = ERR_COUNT;
+        do {
+            bdm_clk(BDM_NOP, CMD_BIT_COUNT);
+        } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
+
+        // save the result
+        if (bdm_response < BDM_NOTREADY) {
+            (*result) <<= 16;
+            (*result) |= bdm_response;
+        } else {
+            // result was not received
+            return false;
+        }
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a write command to MCU.
+
+    @param        num_words        number of additional command words
+    @param        cmd                command sequence
+
+    @return                        succ / fail
+*/
+bool bdm_write(const uint32_t* addr, uint16_t cmd, const uint32_t* value) {
+    // write command code
+    bdm_clk(cmd, CMD_BIT_COUNT);
+    if (bdm_response > BDM_NOTREADY) {
+        return false;
+    }
+
+    // write the optional address
+    if (addr) {
+        // first word
+        bdm_clk((uint16_t)((*addr) >> 16), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+        // second word
+        bdm_clk((uint16_t)(*addr), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+    }
+
+    // write the value
+    if (cmd & BDM_LONGSIZE) {
+        bdm_clk((uint16_t)((*value) >> 16), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+    }
+    bdm_clk((uint16_t)(*value), CMD_BIT_COUNT);
+    if (bdm_response > BDM_NOTREADY) {
+        return false;
+    }
+
+    // wait until MCU responds
+    uint8_t wait_cnt = ERR_COUNT;
+    do {
+        // read response
+        bdm_clk(BDM_NOP, CMD_BIT_COUNT);
+    } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
+
+    // check if command succeeded
+    return (bdm_response == BDM_CMDCMPLTE);
+}
+
+bool bdm_command (uint16_t cmd) {
+    // write command code
+    bdm_clk(cmd, CMD_BIT_COUNT);
+    return (bdm_response > BDM_NOTREADY) ? false : true;
+}
+
+bool bdm_address (const uint32_t* addr) {
+    // write an address
+    // first word
+    bdm_clk((uint16_t)((*addr) >> 16), CMD_BIT_COUNT);
+    if (bdm_response > BDM_NOTREADY) {
+        return false;
+    }
+    // second word
+    bdm_clk((uint16_t)(*addr), CMD_BIT_COUNT);
+    return (bdm_response > BDM_NOTREADY) ? false : true;
+}
+
+bool bdm_get (uint32_t* result, uint8_t size, uint16_t next_cmd) {
+    // receive response words
+    *result = 0;
+    uint8_t wait_cnt;
+    for (uint8_t curr_word = 0; curr_word < ((size & BDM_LONGSIZE) ? 2 : 1);
+            ++curr_word) {
+        // wait while MCU prepares the response
+        wait_cnt = ERR_COUNT;
+        do {
+            bdm_clk(next_cmd, CMD_BIT_COUNT);
+        } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
+
+        // save the result
+        if (bdm_response < BDM_NOTREADY) {
+            (*result) <<= 16;
+            (*result) |= bdm_response;
+        } else {
+            // result was not received
+            return false;
+        }
+    }
+    return true;
+}
+
+bool bdm_put (const uint32_t* value, uint8_t size) {
+    // write the value
+    if (size & BDM_LONGSIZE) {
+        bdm_clk((uint16_t)((*value) >> 16), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+    }
+    bdm_clk((uint16_t)(*value), CMD_BIT_COUNT);
+    return (bdm_response > BDM_NOTREADY) ? false : true;
+}
+
+bool bdm_ready (uint16_t next_cmd) {
+    // wait until MCU responds
+    uint8_t wait_cnt = ERR_COUNT;
+    do {
+        // read response
+        bdm_clk(next_cmd, CMD_BIT_COUNT);
+    } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
+
+    // check if command succeeded
+    return (bdm_response == BDM_CMDCMPLTE);
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a word to target MCU via BDM line and gets the response.
+
+    @param            value            value to write
+    @param            num_bits        value size, bits
+*/
+void bdm_clk(uint16_t value, uint8_t num_bits) {
+//    PIN_BKPT.output();
+//    PIN_DSI.output();
+    LPC_GPIO2->FIODIR |= 0x00000004;
+    // clock the value via BDM
+    bdm_response = ((uint32_t)value) << (32 - num_bits);
+//    bool dsi;
+
+    while (num_bits--) {
+
+        // falling edge on BKPT/DSCLK
+        PIN_BKPT.write(0);
+
+        // set DSI bit
+        PIN_DSI.write(bdm_response & 0x80000000);
+        bdm_response <<= 1;
+
+        // read DSO bit
+        bdm_response |= PIN_DSO.read();
+
+        // short delay
+//        for (uint8_t c = 1; c; c--);
+//        wait_us(1);
+
+        // rising edge on BKPT/DSCLK
+        PIN_BKPT.write(1);
+
+        // short delay
+        for (uint8_t c = 1; c; c--);
+//        wait_us(1);
+    }
+
+    PIN_DSI.input();
+//    LPC_GPIO2->FIODIR &= 0xfffffffb;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Clears the BDM interface after errors.
+*/
+void bdm_clear() {
+    bdm_clk (BDM_NOP, CMD_BIT_COUNT);
+    bdm_clk (BDM_NOP, CMD_BIT_COUNT);
+    bdm_clk (BDM_NOP, CMD_BIT_COUNT);
+    bdm_clk (BDM_NOP, CMD_BIT_COUNT);
+
+    while (bdm_response > 0) {
+        bdm_clk(0, 1);
+    }
+    while (bdm_response < 1) {
+        bdm_clk(0, 1);
+    }
+    bdm_clk(0, 15);
+}
+
+//-----------------------------------------------------------------------------
+//    EOF
+//-----------------------------------------------------------------------------