├── .gitignore ├── CMakeLists.txt ├── DebugPort.hpp ├── STM32.hpp ├── README ├── SWD.hpp ├── MemoryAccessPort.hpp ├── LICENSE ├── STM32.cpp ├── DebugPort.cpp ├── MemoryAccessPort.cpp ├── SWD.cpp └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | /build 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | project(rpi-swd) 3 | cmake_minimum_required(VERSION 2.6.0) 4 | 5 | set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Woverloaded-virtual -std=c++0x") 6 | 7 | set(SRC 8 | DebugPort.cpp 9 | DebugPort.hpp 10 | main.cpp 11 | MemoryAccessPort.cpp 12 | MemoryAccessPort.hpp 13 | STM32.cpp 14 | STM32.hpp 15 | SWD.cpp 16 | SWD.hpp 17 | ) 18 | 19 | add_executable(rpi-swd ${SRC}) 20 | target_link_libraries(rpi-swd wiringPi) 21 | -------------------------------------------------------------------------------- /DebugPort.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DEBUGPORT_HPP_INCLUDED 3 | #define DEBUGPORT_HPP_INCLUDED 4 | 5 | #include 6 | 7 | class SWD; 8 | 9 | class DebugPort { 10 | public: 11 | DebugPort(SWD *swd); 12 | ~DebugPort(); 13 | 14 | uint32_t getIdCode(); 15 | 16 | uint32_t getStatus(); 17 | 18 | void select(unsigned int apSel, unsigned int apBank); 19 | 20 | uint32_t readRB(); 21 | uint32_t readAP(unsigned int apSel, unsigned int address); 22 | void writeAP(unsigned int apSel, unsigned int address, uint32_t value); 23 | private: 24 | SWD *swd; 25 | unsigned int currentAP; 26 | unsigned int currentBank; 27 | }; 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /STM32.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef STM32_HPP_INCLUDED 3 | #define STM32_HPP_INCLUDED 4 | 5 | #include 6 | 7 | class DebugPort; 8 | class MemoryAccessPort; 9 | 10 | class STM32 { 11 | public: 12 | STM32(DebugPort *debugPort); 13 | ~STM32(); 14 | 15 | void halt(); 16 | void unhalt(); 17 | void reset(); 18 | 19 | void unlockFlash(); 20 | void lockFlash(); 21 | 22 | void startProgramming(); 23 | void endProgramming(); 24 | 25 | void eraseFlash(uint32_t page); 26 | void eraseFlash(); 27 | 28 | void waitFlash(); 29 | 30 | MemoryAccessPort *getAHB() { 31 | return ahb; 32 | } 33 | private: 34 | MemoryAccessPort *ahb; 35 | }; 36 | 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | About 3 | ===== 4 | 5 | This is programmer for the STM32F051 microcontroller which is designed to run 6 | on the Raspberry Pi. It uses the Serial Wire Debug protocol which is a two-wire 7 | connection which is mostly compatible to JTAG. 8 | 9 | Currently the code only implements programming the firmware into flash, other 10 | operations might be implemented in the future. As the protocol is bit-banged 11 | and does not have any reliable form of error detection, the quality of the 12 | result generally will vary. 13 | 14 | The code has been shamelessly copied^H^Hinspired from the pirate-swd project 15 | which implements the protocol for the Bus Pirate. 16 | https://github.com/willdonnelly/pirate-swd 17 | 18 | -------------------------------------------------------------------------------- /SWD.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SWD_HPP_INCLUDED 3 | #define SWD_HPP_INCLUDED 4 | 5 | #include 6 | 7 | class SWD { 8 | public: 9 | SWD(unsigned int frequency = 50000); 10 | ~SWD(); 11 | 12 | /** 13 | * Resets the microcontroller. 14 | */ 15 | void reset(); 16 | /** 17 | * Sends 50 "1"s and 8 "0"s to resynchronize with the microcontroller. 18 | */ 19 | void resync(); 20 | 21 | uint32_t read(bool ap, int reg); 22 | void write(bool ap, int reg, uint32_t value); 23 | private: 24 | void writeBit(int value); 25 | int readBit(); 26 | void clock(); 27 | 28 | int writeCommand(bool ap, int read, int reg); 29 | 30 | void error(); 31 | 32 | unsigned int tdiv2; 33 | 34 | int errors; 35 | }; 36 | 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /MemoryAccessPort.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MEMORY_ACCESS_PORT_HPP_INCLUDED 3 | #define MEMORY_ACCESS_PORT_HPP_INCLUDED 4 | 5 | #include 6 | 7 | class DebugPort; 8 | 9 | class MemoryAccessPort { 10 | public: 11 | MemoryAccessPort(DebugPort *debugPort, unsigned int apSel); 12 | ~MemoryAccessPort(); 13 | 14 | uint32_t getIdCode(); 15 | 16 | uint32_t readWord(uint32_t address); 17 | uint32_t writeWord(uint32_t address, uint32_t value); 18 | 19 | uint32_t readHalf(uint32_t address); 20 | uint32_t writeHalf(uint32_t address, uint32_t value); 21 | 22 | void readBlock(uint32_t address, uint32_t count, uint32_t *buffer); 23 | void writeBlock(uint32_t address, uint32_t count, const uint32_t *buffer); 24 | void writeBlockNonInc(uint32_t address, 25 | uint32_t count, 26 | const uint32_t *buffer); 27 | void writeHalfs(uint32_t address, uint32_t count, const uint32_t *buffer); 28 | void writeHalfsVerify(uint32_t address, uint32_t count, const uint32_t *buffer); 29 | private: 30 | void csw(unsigned int addrInc, unsigned int size); 31 | 32 | DebugPort *debugPort; 33 | unsigned int apSel; 34 | }; 35 | 36 | #endif 37 | 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Will Donnelly, Mathias Gottschlag 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | * Neither the name of the software nor the names of its contributors may be used 13 | to endorse or promote products derived from this software without specific 14 | prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS- 19 | CLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /STM32.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "STM32.hpp" 3 | #include "MemoryAccessPort.hpp" 4 | 5 | #include 6 | 7 | static const uint32_t FLASH_BASE = 0x40022000; 8 | 9 | static const uint32_t FLASH_KEYR = FLASH_BASE + 0x04; 10 | static const uint32_t FLASH_SR = FLASH_BASE + 0x0c; 11 | static const uint32_t FLASH_CR = FLASH_BASE + 0x10; 12 | static const uint32_t FLASH_AR = FLASH_BASE + 0x14; 13 | 14 | STM32::STM32(DebugPort *debugPort) { 15 | ahb = new MemoryAccessPort(debugPort, 0); 16 | } 17 | STM32::~STM32() { 18 | delete ahb; 19 | } 20 | 21 | void STM32::halt() { 22 | ahb->writeWord(0xE000EDF0, 0xA05F0003); 23 | } 24 | void STM32::unhalt() { 25 | ahb->writeWord(0xE000EDF0, 0xA05F0000); 26 | } 27 | void STM32::reset() { 28 | ahb->writeWord(0xE000ED0C, 0x05FA0004); 29 | } 30 | 31 | void STM32::unlockFlash() { 32 | ahb->writeWord(FLASH_KEYR, 0x45670123); 33 | ahb->writeWord(FLASH_KEYR, 0xcdef89ab); 34 | } 35 | void STM32::lockFlash() { 36 | ahb->writeWord(FLASH_CR, ahb->readWord(FLASH_CR) | (1 << 7)); 37 | } 38 | 39 | void STM32::startProgramming() { 40 | ahb->writeWord(FLASH_CR, 1); 41 | } 42 | void STM32::endProgramming() { 43 | ahb->writeWord(FLASH_CR, 0); 44 | } 45 | 46 | void STM32::eraseFlash(uint32_t page) { 47 | ahb->writeWord(FLASH_CR, 2); 48 | ahb->writeWord(FLASH_AR, page); 49 | ahb->writeWord(FLASH_CR, 0x42); 50 | while ((ahb->readWord(FLASH_SR) & 0x1) != 0) { 51 | usleep(10000); 52 | } 53 | } 54 | 55 | void STM32::eraseFlash() { 56 | // TODO 57 | } 58 | 59 | void STM32::waitFlash() { 60 | while ((ahb->readWord(FLASH_SR) & 0x1) != 0) { 61 | usleep(10000); 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /DebugPort.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "DebugPort.hpp" 3 | #include "SWD.hpp" 4 | 5 | #include 6 | #include 7 | 8 | DebugPort::DebugPort(SWD *swd) : swd(swd) { 9 | // Parse the IDCODE register content 10 | uint32_t idCode = getIdCode(); 11 | if (idCode != 0x0bb11477) { 12 | throw std::runtime_error("Unknown IDCODE."); 13 | } 14 | // Clear any errors 15 | swd->write(false, 0, 0x1e); 16 | // Get the SELECT register to a known state 17 | currentAP = 0; 18 | currentBank = 0; 19 | swd->write(false, 2, 0); 20 | // Enable power 21 | swd->write(false, 1, 0x54000000); 22 | if ((getStatus() >> 24) != 0xF4) { 23 | throw std::runtime_error("Could not enable power."); 24 | } 25 | } 26 | DebugPort::~DebugPort() { 27 | } 28 | 29 | uint32_t DebugPort::getIdCode() { 30 | return swd->read(false, 0); 31 | } 32 | 33 | uint32_t DebugPort::getStatus() { 34 | return swd->read(false, 1); 35 | } 36 | 37 | void DebugPort::select(unsigned int apSel, unsigned int apBank) { 38 | if (apSel == currentAP && apBank == currentBank) { 39 | return; 40 | } 41 | swd->write(false, 2, ((apSel & 0xff) << 24) || ((apBank & 0xf) << 4)); 42 | currentAP = apSel; 43 | currentBank = apBank; 44 | } 45 | 46 | uint32_t DebugPort::readRB() { 47 | return swd->read(false, 3); 48 | } 49 | uint32_t DebugPort::readAP(unsigned int apSel, unsigned int address) { 50 | unsigned int bank = address >> 4; 51 | unsigned int reg = (address >> 2) & 0x3; 52 | select(apSel, bank); 53 | return swd->read(true, reg); 54 | } 55 | void DebugPort::writeAP(unsigned int apSel, unsigned int address, uint32_t value) { 56 | unsigned int bank = address >> 4; 57 | unsigned int reg = (address >> 2) & 0x3; 58 | select(apSel, bank); 59 | swd->write(true, reg, value); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /MemoryAccessPort.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "MemoryAccessPort.hpp" 3 | #include "DebugPort.hpp" 4 | 5 | #include 6 | 7 | MemoryAccessPort::MemoryAccessPort(DebugPort *debugPort, unsigned int apSel) 8 | : debugPort(debugPort), apSel(apSel) { 9 | // Default: 32-bit auto-incrementing 10 | csw(1, 2); 11 | } 12 | MemoryAccessPort::~MemoryAccessPort() { 13 | // TODO 14 | } 15 | 16 | uint32_t MemoryAccessPort::getIdCode() { 17 | debugPort->readAP(apSel, 0xfc); 18 | return debugPort->readRB(); 19 | } 20 | 21 | uint32_t MemoryAccessPort::readWord(uint32_t address) { 22 | debugPort->writeAP(apSel, 0x04, address); 23 | debugPort->readAP(apSel, 0x0c); 24 | return debugPort->readRB(); 25 | } 26 | uint32_t MemoryAccessPort::writeWord(uint32_t address, uint32_t value) { 27 | debugPort->writeAP(apSel, 0x04, address); 28 | debugPort->writeAP(apSel, 0x0c, value); 29 | return debugPort->readRB(); 30 | } 31 | 32 | uint32_t MemoryAccessPort::readHalf(uint32_t address) { 33 | csw(0, 1); 34 | debugPort->writeAP(apSel, 0x04, address); 35 | debugPort->readAP(apSel, 0x0c); 36 | csw(1, 2); 37 | return debugPort->readRB(); 38 | } 39 | uint32_t MemoryAccessPort::writeHalf(uint32_t address, uint32_t value) { 40 | csw(1, 1); 41 | debugPort->writeAP(apSel, 0x04, address); 42 | debugPort->writeAP(apSel, 0x0c, value); 43 | debugPort->writeAP(apSel, 0x0c, value); 44 | csw(1, 2); 45 | return debugPort->readRB(); 46 | } 47 | 48 | void MemoryAccessPort::readBlock(uint32_t address, 49 | uint32_t count, 50 | uint32_t *buffer) { 51 | debugPort->writeAP(apSel, 0x04, address); 52 | debugPort->readAP(apSel, 0x0c); 53 | for (unsigned int i = 0; i < count - 1; i++) { 54 | buffer[i] = debugPort->readAP(apSel, 0x0c); 55 | } 56 | buffer[count - 1] = debugPort->readRB(); 57 | } 58 | void MemoryAccessPort::writeBlock(uint32_t address, 59 | uint32_t count, 60 | const uint32_t *buffer) { 61 | debugPort->writeAP(apSel, 0x04, address); 62 | for (unsigned int i = 0; i < count; i++) { 63 | debugPort->writeAP(apSel, 0x0c, buffer[i]); 64 | } 65 | } 66 | void MemoryAccessPort::writeBlockNonInc(uint32_t address, 67 | uint32_t count, 68 | const uint32_t *buffer) { 69 | // 32-bit non-incrementing addressing 70 | csw(0, 2); 71 | writeBlock(address, count, buffer); 72 | // 32-bit auto-incrementing addressing 73 | csw(1, 2); 74 | } 75 | void MemoryAccessPort::writeHalfs(uint32_t address, 76 | uint32_t count, 77 | const uint32_t *buffer) { 78 | // 16-bit auto-incrementing addressing 79 | csw(1, 1); 80 | debugPort->writeAP(apSel, 0x04, address); 81 | for (unsigned int i = 0; i < count; i++) { 82 | debugPort->writeAP(apSel, 0x0c, buffer[i]); 83 | debugPort->writeAP(apSel, 0x0c, buffer[i]); 84 | } 85 | /*// 16-bit packed-incrementing addressing 86 | csw(2, 1); 87 | writeBlock(address, count, buffer);*/ 88 | // 32-bit auto-incrementing addressing 89 | csw(1, 2); 90 | } 91 | 92 | void MemoryAccessPort::csw(unsigned int addrInc, unsigned int size) { 93 | debugPort->readAP(apSel, 0x00); 94 | uint32_t csw = debugPort->readRB() & 0xFFFFFF00; 95 | debugPort->writeAP(apSel, 0x00, csw + (addrInc << 4) + size); 96 | } 97 | -------------------------------------------------------------------------------- /SWD.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SWD.hpp" 3 | 4 | #include 5 | #include 6 | 7 | /** 8 | * SWD clock pin (with pulldown in the microcontroller). 9 | */ 10 | static const int SWCLK = 12; 11 | /** 12 | * SWD data pin (with pullup in the microcontroller). 13 | */ 14 | static const int SWDAT = 13; 15 | /** 16 | * Microcontroller reset line (active low and with pullup in the 17 | * microcontroller). 18 | */ 19 | static const int NRST = 14; 20 | 21 | static const int ACK_OK = 0x4; 22 | static const int ACK_WAIT = 0x2; 23 | static const int ACK_FAULT = 0x1; 24 | 25 | #include 26 | 27 | SWD::SWD(unsigned int frequency) : errors(0) { 28 | tdiv2 = 1000000 / (frequency / 2); 29 | std::cout << "tdiv2: " << tdiv2 << std::endl; 30 | 31 | if (wiringPiSetup() == -1) { 32 | throw std::runtime_error("Could not initialize wiringPi."); 33 | } 34 | // We are doing realtime bitbanging - this might help a little bit 35 | piHiPri(99); 36 | 37 | pinMode(SWDAT, OUTPUT); 38 | digitalWrite(SWDAT, 0); 39 | pinMode(SWCLK, OUTPUT); 40 | digitalWrite(SWCLK, 0); 41 | 42 | reset(); 43 | resync(); 44 | } 45 | SWD::~SWD() { 46 | } 47 | 48 | void SWD::reset() { 49 | pinMode(NRST, OUTPUT); 50 | digitalWrite(NRST, 0); 51 | delay(200); 52 | pinMode(NRST, INPUT); 53 | } 54 | void SWD::resync() { 55 | for (unsigned int i = 0; i < 50; i++) { 56 | writeBit(1); 57 | } 58 | writeBit(0); 59 | // The reference says that we have to read IDCODE here 60 | read(false, 0); 61 | } 62 | 63 | uint32_t SWD::read(bool ap, int reg) { 64 | int ack = writeCommand(ap, 1, reg); 65 | if (ack == ACK_OK) { 66 | uint32_t value = 0; 67 | int parity = 0; 68 | for (unsigned int i = 0; i < 32; i++) { 69 | value >>= 1; 70 | int bit = readBit(); 71 | value |= bit << 31; 72 | parity ^= bit; 73 | } 74 | if (parity == readBit()) { 75 | pinMode(SWDAT, OUTPUT); 76 | writeBit(0); 77 | errors = std::max(errors - 1, 0); 78 | return value; 79 | } 80 | std::cout << "value: " << std::hex << value << std::endl; 81 | } else if (ack == ACK_FAULT) { 82 | for (unsigned int i = 0; i < 33; i++) { 83 | clock(); 84 | } 85 | pinMode(SWDAT, OUTPUT); 86 | writeBit(0); 87 | /*throw std::runtime_error("ACK_FAULT");*/ 88 | std::cout << "ACK_FAULT" << std::endl; 89 | error(); 90 | return read(ap, reg); 91 | } else if (ack == ACK_WAIT) { 92 | /*for (unsigned int i = 0; i < 33; i++) { 93 | clock(); 94 | }*/ 95 | // Just try again until the command succeeds 96 | /*pinMode(SWDAT, OUTPUT); 97 | return read(ap, reg);*/ 98 | errors -= 2; 99 | } 100 | std::cout << "read ack: " << ack << std::endl; 101 | error(); 102 | pinMode(SWDAT, OUTPUT); 103 | resync(); 104 | return read(ap, reg); 105 | } 106 | void SWD::write(bool ap, int reg, uint32_t value) { 107 | int parity = __builtin_parity(value); 108 | int ack = writeCommand(ap, 0, reg); 109 | if (ack == ACK_OK) { 110 | clock(); 111 | pinMode(SWDAT, OUTPUT); 112 | uint32_t tmpValue = value; 113 | for (unsigned int i = 0; i < 32; i++) { 114 | writeBit(tmpValue & 0x1); 115 | tmpValue >>= 1; 116 | } 117 | writeBit(parity); 118 | writeBit(0); 119 | errors = std::max(errors - 1, 0); 120 | return; 121 | } else if (ack == ACK_FAULT) { 122 | throw std::runtime_error("ACK_FAULT"); 123 | } else if (ack == ACK_WAIT) { 124 | // Just try again until the command succeeds 125 | /*clock(); 126 | pinMode(SWDAT, OUTPUT); 127 | for (unsigned int i = 0; i < 32; i++) { 128 | writeBit(0); 129 | } 130 | write(ap, reg, value); 131 | return;*/ 132 | errors -= 2; 133 | } 134 | std::cout << "write ack: " << ack << std::endl; 135 | //throw std::runtime_error("test"); 136 | error(); 137 | pinMode(SWDAT, OUTPUT); 138 | resync(); 139 | write(ap, reg, value); 140 | } 141 | 142 | void SWD::writeBit(int value) { 143 | digitalWrite(SWCLK, 1); 144 | delayMicroseconds(tdiv2); 145 | digitalWrite(SWDAT, value); 146 | digitalWrite(SWCLK, 0); 147 | delayMicroseconds(tdiv2); 148 | } 149 | int SWD::readBit() { 150 | digitalWrite(SWCLK, 1); 151 | delayMicroseconds(tdiv2); 152 | int value = digitalRead(SWDAT); 153 | digitalWrite(SWCLK, 0); 154 | delayMicroseconds(tdiv2); 155 | return value; 156 | } 157 | void SWD::clock() { 158 | digitalWrite(SWCLK, 1); 159 | delayMicroseconds(tdiv2); 160 | digitalWrite(SWCLK, 0); 161 | delayMicroseconds(tdiv2); 162 | } 163 | 164 | int SWD::writeCommand(bool ap, int read, int reg) { 165 | writeBit(1); 166 | writeBit(ap ? 1 : 0); 167 | writeBit(read); 168 | writeBit(reg & 0x1); 169 | writeBit((reg >> 1) & 0x1); 170 | int parity = (ap ? 1 : 0) + read + (reg & 0x1) + ((reg >> 1) & 0x1); 171 | writeBit(parity & 0x1); 172 | writeBit(0); 173 | pinMode(SWDAT, INPUT); 174 | /*if (reg == 1) { 175 | uint32_t data = 0; 176 | for (unsigned int i = 0; i < 32; i++) { 177 | data <<= 1; 178 | data |= readBit(); 179 | } 180 | std::cout << std::hex << data << std::endl; 181 | }*/ 182 | clock(); 183 | clock(); 184 | int ack = readBit() << 2; 185 | ack |= readBit() << 1; 186 | ack |= readBit(); 187 | return ack; 188 | } 189 | 190 | void SWD::error() { 191 | errors += 2; 192 | if (errors >= 10) { 193 | throw std::runtime_error("Too many errors."); 194 | } 195 | } 196 | 197 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SWD.hpp" 3 | #include "DebugPort.hpp" 4 | #include "STM32.hpp" 5 | #include "MemoryAccessPort.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char **argv) { 12 | SWD swd(500000); 13 | DebugPort debugPort(&swd); 14 | STM32 stm32(&debugPort); 15 | 16 | uint32_t dpIdCode = debugPort.getIdCode(); 17 | uint32_t apIdCode = stm32.getAHB()->getIdCode(); 18 | uint32_t mcuIdCode = stm32.getAHB()->readWord(0x40015800); 19 | 20 | std::cout << std::hex << std::setfill('0'); 21 | std::cout << "DP.IDCODE: "; 22 | std::cout << std::setw(8) << dpIdCode << std::endl; 23 | std::cout << "AP.IDCODE: "; 24 | std::cout << std::setw(8) << apIdCode << std::endl; 25 | std::cout << "DBGMCU_IDCODE: "; 26 | std::cout << std::setw(8) << mcuIdCode << std::endl; 27 | 28 | if (argc == 1) { 29 | return 0; 30 | } 31 | 32 | #if 1 33 | // Read the input file 34 | std::cout << "Reading program file..." << std::endl; 35 | char buffer[1 << 16]; 36 | std::ifstream programFile(argv[1], std::ios_base::binary); 37 | if (!programFile) { 38 | std::cerr << "Could not open program file!" << std::endl; 39 | return -1; 40 | } 41 | programFile.read(buffer, 1 << 16); 42 | unsigned int size = programFile.gcount(); 43 | size = (size + 3) & ~3; 44 | std::cout << "Program: " << std::dec << size << " bytes." << std::endl; 45 | programFile.close(); 46 | 47 | std::cout << "Halting the processor..." << std::endl; 48 | stm32.halt(); 49 | std::cout << "Unlocking the program memory..." << std::endl; 50 | stm32.unlockFlash(); 51 | std::cout << "Erasing previous content..." << std::endl; 52 | for (unsigned int i = 0; i < ((size + 0x3ff) & ~0x3ff); i += 0x400) { 53 | std::cout << "Erasing " << std::hex << 0x08000000 + i << std::endl; 54 | stm32.eraseFlash(0x08000000 + i); 55 | for (unsigned int j = 0; j < 0x400; j += 4) { 56 | uint32_t erase = stm32.getAHB()->readWord(0x08000000 + i + j); 57 | if (erase != 0xffffffff) { 58 | std::cout << "Erasing failed at " << std::hex << 0x08000000 + i + j << std::endl; 59 | } 60 | } 61 | } 62 | std::cout << "Programming..." << std::endl; 63 | stm32.startProgramming(); 64 | for (unsigned int i = 0; i < size; i += 4) { 65 | stm32.getAHB()->writeHalf(0x08000000 + i, *(uint32_t*)(buffer + i)); 66 | stm32.waitFlash(); 67 | uint32_t value = stm32.getAHB()->readWord(0x08000000 + i); 68 | if (value != *(uint32_t*)(buffer + i)) { 69 | std::cout << "Programming failed at " << std::hex << 0x08000000 + i << std::endl; 70 | std::cout << "Difference: " << *(uint32_t*)(buffer + i) << "/" << value << std::endl; 71 | } 72 | } 73 | //stm32.getAHB()->writeHalfs(0x08000000, size >> 2, (uint32_t*)buffer); 74 | stm32.endProgramming(); 75 | std::cout << "Verifying memory content..." << std::endl; 76 | char *download = new char[size]; 77 | //stm32.getAHB()->readBlock(0x08000000, size >> 2, (uint32_t*)download); 78 | for (unsigned int i = 0; i < size >> 2; i++) { 79 | ((uint32_t*)download)[i] = stm32.getAHB()->readWord(0x08000000 + (i << 2)); 80 | } 81 | for (unsigned int i = 0; i < size; i++) { 82 | if (buffer[i] != download[i]) { 83 | std::cout << "Error at byte " << std::dec << i << ": "; 84 | std::cout << std::hex << (unsigned int)buffer[i] 85 | << "/" << (unsigned int)download[i] << std::endl; 86 | } 87 | } 88 | delete[] download; 89 | std::cout << "Resetting the processor..." << std::endl; 90 | stm32.unhalt(); 91 | stm32.reset(); 92 | std::cout << "Done." << std::endl; 93 | #endif 94 | 95 | #if 0 96 | uint32_t oldValue = stm32.getAHB()->readWord(0x20001000); 97 | stm32.getAHB()->writeWord(0x20001000, 0xdeadc0de); 98 | uint32_t newValue = stm32.getAHB()->readWord(0x20001000); 99 | 100 | std::cout << "Memory: " << std::hex << oldValue << "/" << newValue << std::endl; 101 | 102 | //uint32_t test[] = { 0x12345678, 0x5634129a, 0xabcdefab }; 103 | //stm32.getAHB()->writeHalfs(0x20001004, 3, test); 104 | stm32.getAHB()->writeHalf(0x20001004, 0x12345678); 105 | stm32.getAHB()->writeHalf(0x20001008, 0x9abcdef0); 106 | newValue = stm32.getAHB()->readWord(0x20001004); 107 | std::cout << "Memory: " << std::hex << newValue << std::endl; 108 | newValue = stm32.getAHB()->readWord(0x20001008); 109 | std::cout << "Memory: " << std::hex << newValue << std::endl; 110 | newValue = stm32.getAHB()->readWord(0x2000100c); 111 | std::cout << "Memory: " << std::hex << newValue << std::endl; 112 | 113 | stm32.halt(); 114 | oldValue = stm32.getAHB()->readWord(0x40022010); 115 | stm32.unlockFlash(); 116 | newValue = stm32.getAHB()->readWord(0x40022010); 117 | std::cout << "Flash: " << std::hex << oldValue << "/" << newValue << std::endl; 118 | 119 | /*uint32_t test[] = { 0x12345678, 0x5634129a, 0xabcdefab }; 120 | stm32.getAHB()->writeHalfs(0x08000000, 3, test);*/ 121 | newValue = stm32.getAHB()->readWord(0x08000000); 122 | std::cout << "Memory: " << std::hex << newValue << std::endl; 123 | newValue = stm32.getAHB()->readWord(0x08000004); 124 | std::cout << "Memory: " << std::hex << newValue << std::endl; 125 | newValue = stm32.getAHB()->readWord(0x08000008); 126 | std::cout << "Memory: " << std::hex << newValue << std::endl; 127 | 128 | //stm32.eraseFlash(0x08000000); 129 | 130 | newValue = stm32.getAHB()->readWord(0x08000000); 131 | std::cout << "Memory: " << std::hex << newValue << std::endl; 132 | newValue = stm32.getAHB()->readWord(0x08000004); 133 | std::cout << "Memory: " << std::hex << newValue << std::endl; 134 | newValue = stm32.getAHB()->readWord(0x08000008); 135 | std::cout << "Memory: " << std::hex << newValue << std::endl; 136 | #endif 137 | 138 | return 0; 139 | } 140 | 141 | --------------------------------------------------------------------------------