Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: bdmcpu32.cpp
- Revision:
- 1:d5452e398b76
- Child:
- 2:bf3a2b29259a
diff -r e0b964252a05 -r d5452e398b76 bdmcpu32.cpp
--- /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
+//-----------------------------------------------------------------------------