Flash an MCU from another MCU (over SWD) - Page 1
Forum section: electronics / general

author: Saimoun
author_rank: Frequent Contributor
timestamp: December 18, 2022, 06:24:10 pm
content: HiSay I have MCU 1, a Cortex M4, with an SWD interface.I want to program MCU 1 with another MCU (2) over SWD. MCU 2 will have the entire firmware of MCU 1 stored somewhere in its flash.I was thinking taking the CMSIS-DAP implementation and remove the USB part, sending the bytes stored in flash over the SWD instead.Any feedback, ideas? Has maybe anyone done that already?CheersSimon

author: pcprogrammer
author_rank: Super Contributor
timestamp: December 18, 2022, 06:32:45 pm
content: Not sure if this is possible with the SWD connection. The ST-Link uses a clock and data line if I'm not mistaken.Action number one would be to see what can be done over the SWD wire. If it can do the programming, then it should not be that hard, because the ST-Link also has a MCU in it. The difference is that the data to be flashed is written via the USB connection.Maybe there is an open source project for the ST-Link somewhere on the net.

author: ataradov
author_rank: Super Contributor
timestamp: December 18, 2022, 06:37:34 pm
content: It is very easy to do. I have an example project that does this -https://github.com/ataradov/embedded-swdSWD link is standard across all ARM MCUs and once established it gives you access to the device memory map. The target MCU in this case is SAM D21, for your MCU you would need to change the code in dap_target.c to implement programming function that use flash controller of your target device.

author: pcprogrammer
author_rank: Super Contributor
timestamp: December 18, 2022, 06:48:20 pm
content: What am I mistaken with then? Thought that SWD stood for single wire debug interface and therefore only used a single wire plus ground, of course, for the communication.Your github mentions SWCLK and SWDIO, which is what the ST-Link also uses.

author: Saimoun
author_rank: Frequent Contributor
timestamp: December 18, 2022, 06:50:30 pm
content: Ahhhh Alex - you save me once moreAwesome, I will have a look, thank you so much!!pcprogrammer: yes the idea is to do exactly like an ST-Link, but without the USB partThe SWCLK and SWDIO pins are used on the target side, I am not sure about the programmer's side but I would guess they use normal IO pins.

author: ataradov
author_rank: Super Contributor
timestamp: December 18, 2022, 06:57:13 pm
content: SWD is serial wire debug. It always used data and clock. It is what all debuggers use for ARM.That's what the linked project is - just the DAP part from the standard debugger firmware.The programming algorithm depends on your target device. But all ST devices are very similar, and you can look at a couple implementations herehttps://github.com/ataradov/edbg/blob/master/target_st_stm32g0.cand herehttps://github.com/ataradov/edbg/blob/master/target_gd_gd32f4xx.c(for GigaDevice version, but the principle is the same)

author: pcprogrammer
author_rank: Super Contributor
timestamp: December 18, 2022, 07:28:59 pm
content: You have to log in to fully read it but here they do talk about "single wire debug", but it is for ARM7 and ARM9.https://ieeexplore.ieee.org/document/9184647But is there not also an extra wire for debug print onto a asynchronous receiver?I really have to get the datasheets out and do some STM32 projects again.

author: ataradov
author_rank: Super Contributor
timestamp: December 18, 2022, 07:35:30 pm
content: I'm not going to pay for that and I don't have an account. But given that they talk about ARM7 and ARM9 processors, it must very outdated and irrelevant. I also don't think there were ever pin limited devices based on ARM7 orARM9. It is possible that current SWD is continuation of whatever was proposed in that article.I'm not clear why in 2020 anyone would care about this stuff and bother to present it at some conference.SWO pin is optional and is not needed for programming.This site links to the IEEE article, but has pictures from the article in the clearhttps://www.semanticscholar.org/paper/Single-Wire-Debug-Interface-Singh-Patil/9814ba760c8fc20bf1b891c0d44f25a8518252ddThe first picture shows bidirectional I/O pin along with the clock. This is some academic nonsense, can be safely ignored as most stuff published by IEEE. Just academics padding their publications count with random junk.

author: pcprogrammer
author_rank: Super Contributor
timestamp: December 18, 2022, 07:49:18 pm
content: Quote from: ataradov on December 18, 2022, 07:35:30 pmThat is the one

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 18, 2022, 09:34:53 pm
content: Quote from: pcprogrammer on December 18, 2022, 07:49:18 pmCertainly not needed. Another pin that is not necessarily needed either (but you have to check or design your firmware appropriately) is the RESET pin.Check your MCU manual. In many cases, SWD is accessible at any time. The exception is usually simple - SWD usually cannot be accessed when there is no clock running, which can be the case in some low-power modes. So if you use one of these modes where the core clock is stopped, SWD may not be accessible at all, which thus requires an external reset. But that depends on the MCU, so something to check. Also, some for STM32 MCUs, you can configure some register to make SWD functional even when the MCU is in 'stop' mode.And now if you have full control over the flashing process and thus in which state the MCU to be flashed is when the flashing must occur, there is zero need for a RESET signal.

author: tellurium
author_rank: Frequent Contributor
timestamp: December 19, 2022, 12:01:42 am
content: There is a commercial solution remote SWD programming:https://vcon.ioMCU1 (ESP32) acts as a remote programmer + transparent UART/MQTT bridge for the MCU2 (STM32, SAMx21/51, RP2040).Disclosure: I work for the company that developed it.

author: djacobow
author_rank: Super Contributor
timestamp: December 19, 2022, 12:36:22 am
content: The question asked was about flashing an MCE from an MCU, but if that "parent" MCU is running linux and has GPIO, it is really easy to build OpenOCD for it and use that to program your target. I have done it for the RPi (like in Ataradov's example) and various other SBC's running linux. In fact, I use such a setup every day.

author: DavidAlfa
author_rank: Super Contributor
timestamp: December 19, 2022, 04:21:27 am
content: You can also use the embedded bootloader and flash it using UART, all you need to do is to set boot0 high and reset the stm32.AN3155: USART protocolhttps://github.com/mengguang/esp8266_stm32_isp

author: eutectique
author_rank: Frequent Contributor
timestamp: December 19, 2022, 12:12:20 pm
content: Quote from: simonlasnier on December 18, 2022, 06:24:10 pmThis is exactly how development kits do it. Take, for example,SAM C21 Xplained Pro, ornRF52 DK, orSTM32 Disco.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: December 19, 2022, 03:34:41 pm
content: SiLabs has a public standalone SWD programmer project:https://www.silabs.com/documents/public/application-notes/AN1011-efm32-standalone-programmer.pdf

author: westfw
author_rank: Super Contributor
timestamp: December 19, 2022, 08:32:47 pm
content: QuoteI don't think that anyone so far as sufficiently stressed that SWD does NOT give you access to the flash memory of the chip directly, or in any vendor-independent fashion. For each "target" chip, you must write commands to the NVM Controller that are specific to that particular chip. I think you have a choice of manipulating the NVMC and memory directly, or writing short programs that reside in RAM, and then running them, but I haven't looked into the details of how it's "usually" done.

author: ataradov
author_rank: Super Contributor
timestamp: December 19, 2022, 08:43:12 pm
content: I mentioned it in the initial post and then post #5.Running small programs is the worst idea ever. It was created by tool vendors (IAR/Keil) because they did not want to maintain programming algorithms for all the devices and wanted to pawn the flash loaders to the device vendors. Just use the controller directly. Some device are worse than others and require consistent uninterrupted supply of data for fast programming, but it is all solvable without flash loaders. Worst case scenario there are always slower word by word programming modes.

author: westfw
author_rank: Super Contributor
timestamp: December 19, 2022, 08:59:38 pm
content: QuoteHmm. Why is it a bad idea? I'm talking about code that writes a chunk of flash, not a full-fledged bootloader than needs a separate communications path. Wouldn't it be something like 1k of code (once) and a 1k of data (repeat till done.) Something like:Code:const flashData[] = { /* data to be uploaded */};const flashAddr = 0x00001000; /* the 2nd 4k */int main() {nvic_program_flash(flashAddr, flashData, sizeof(flashData));bkpt();}

author: ataradov
author_rank: Super Contributor
timestamp: December 19, 2022, 09:21:33 pm
content: Because you need to communicate with this program and your programmer becomes more complicated because now it has to coordinate with the running core and be a more complete debugger instead of being the only master on the bus. And there is virtually no advantages, especially for better designed flash controllers.Plus you need to write, maintain and compile the flash loaders. And the code for the exiting ones is always outdated and does not build right away because it is not the code anyone remember to maintain as long as there are binaries that work.And if you are going to go the flash loader route, it is easier to do what existing ones do - just run an infinite loop and never exit. The communication with the debugger happens though a mailbox memory as a fixed address. Debugger writes the data, writes the command and polls for response. The firmware polls for the command and provides a response when ready. There is no reason for it to ever exit and it simplifies the debugger part.This still only has the advantage to the tool vendors, since they don't need to bother implementing any of this themselves, they just define the protocol/mailbox structure. In all other respects this approach is wirse.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: December 19, 2022, 11:29:41 pm
content: Btw, with direct NVMC interaction method it should be possible to avoid core debug-related stuff (ROM table parsing, DBG regs access etc) completely - just crash the core by setting VTOR (fixed E000ED08 location on all Cortex-Ms) to point to NX mem (like F0000000), then triggering an IRQ via NVIC.

author: ataradov
author_rank: Super Contributor
timestamp: December 19, 2022, 11:40:28 pm
content: But why? It is trivial to halt the core with two register writes. You don't need to parse anything for that.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: December 19, 2022, 11:56:33 pm
content: But don’t you need to get the “core debug” block location from the ROM table first to know those addresses? Or they are fixed on all Cortex-Ms? (I remember doing that for each core of a multicore Cortex-R)

author: ataradov
author_rank: Super Contributor
timestamp: December 20, 2022, 12:01:22 am
content: It is fixed on all Cortex-Mx devices. In theory it might be different on some future cores and you would have to go though the ROM tables, but in practice for current device it is all the same.And in this case you are not doing a generic debugger, the target device is known in advance.

author: westfw
author_rank: Super Contributor
timestamp: December 20, 2022, 03:25:39 am
content: QuoteMaintain the "flash loader" in the target, or maintain the nvic manipulation in the "programmer" side code - what's the difference? (and in either case, here, the code is embedded in the "programmer" image.)I though breakpoints were a pretty solid hand-off between target and debugger. Not so?Code:Load nvic code + first data block (into RAM)Start.while (more code) {Wait for breakpoint.Load next data block.Resume.}Perhaps "start" is more complex than I'm thinking, and I should be quiet till I've actually implemented something.(But... default clocks are probably OK, and no peripherals other than the NVIC are likely to be needed.)BTW, I think the Teensy3 boards do essentially this sort of thing - on reset a tiny microcontroller (mini54 or MK02) loads a bootloader into the main ARM's RAM, which then runs and (perhaps) downloads the user program via USB. (except I'm not sure whether it uses SWD or a Freescale-specific debug protocol.)

author: ataradov
author_rank: Super Contributor
timestamp: December 20, 2022, 03:48:24 am
content: Maintain the code you are going to upload (the code that actually does the write).If you just use NVM controller directly you need to have DAP controller and the code that writes the flash directly. That's it. All of this builds as part of the same project, there are no standalone components.If you do it your way you still need to have DAP controller, but now you also need a separate project that builds your flash loader code. Now you need to upload that loader code and pass control to it. And only then you write the data through that loader. The flash loader code is maintained as a separate project and in this case would have to be included as a binary blob into the main code. This is a nightmare to maintain.And the flash loader is still unique for each device/family, so you are not saving any effort at all.If you are at the point where you load any code, the actual direct flash programming is trivial. It takes less effort than a separate project for a loader.The only reason flash loaders exist is for the benefit of tool vendors that don't want to maintain the programming algorithms for 100s of devices. And if I were ARM, I would define a simple scripting language that implements programming algorithms as part of the CMSIS package. This way vendors would include that script in the device pack. This would actually help everyone and I don't see anyone objecting. Dealing with those binary blobs is annoying for everyone.And "Wait for breakpoint." and "Resume" is actually quite a bit more logic on top of the basic DAP data transfer. At this point you are implementing a full-blown debugger.

author: peter-h
author_rank: Super Contributor
timestamp: December 20, 2022, 09:49:52 am
content: FWIW, somebody pointed out to me that the only way to do a remotely upgradeable system (OTA) which is 100% brick-proof is to have a second CPU which is SWD capable and can write the FLASH of the primary CPU.

author: Siwastaja
author_rank: Super Contributor
timestamp: December 20, 2022, 10:06:39 am
content: Quote from: peter-h on December 20, 2022, 09:49:52 amNothing is 100% brick-proof. You can still make a bug which sets undesired pins as outputs short-circuiting them, possibly causing damage.With the usual multi-page/sector flash, it's fairly trivial to verify your code in such way you never accidentally clear the working firmware. 99.9% of upgradeable devices in existence work like this, and 99.9% of them never get bricked.I consider such massive added extra complication (of secondary CPU) orders of magnitude more risky.

author: peter-h
author_rank: Super Contributor
timestamp: December 20, 2022, 05:08:38 pm
content: Sure; I've never done this, and on my current system the OTA bricking window is just 300ms out of a total programming time of ~10 secs, but I know somebody whose customer demanded this architecture.Otherwise, it would be fairly unusual to want to build your own SWD debuggerStill, it does amaze me how many people reverse engineer these dirt-cheap dongles... Maybe they are looking for something more reliable? None of the STLINK units (I've used them all, I think) are all that reliable, and they lose contact with the target easily. And their interface to Cube is crap.

author: wek
author_rank: Frequent Contributor
timestamp: December 20, 2022, 05:35:20 pm
content: Reminded me of the original AVRPROG, where an AT90S1200 served as the bootloader to an AT90S8535... In my specimen, the latter failed in an overvoltage event, replaced with an ATMega8535 and it works to this day in production of some rather old products...JW

author: Siwastaja
author_rank: Super Contributor
timestamp: December 20, 2022, 06:19:25 pm
content: Quote from: peter-h on December 20, 2022, 05:08:38 pmYou really don't have multi-page flash available, or you just messed things up for no reason? I mean, normally a "time window" like this does not exist.I mean, I have done that "window of death" thing too, but it was a conscious decision to use a single flash page budget MCU (designed to be used with external flash, but in my project, used without).

author: Nominal Animal
author_rank: Super Contributor
timestamp: December 20, 2022, 06:38:45 pm
content: Quote from: Siwastaja on December 20, 2022, 10:06:39 amAlso, as observed with Teensy MicroMods (manufactured by Sparkfun), the processor-processor connection itself is a possible failure point.(It looks like the MicroMods' PCB is a bit too flexible, causing connection issues with the i.MX RT1062 BGA IC.)I don't have an opinion on what is the most robust approach here, but I like the fact that in the Teensy case, the secondary MKL02 processor has direct access to a LED it can use for flashing a specific pattern indicating type of communication error with the main chip: when a problem does appear, it doesn't just become a silent brick, and you get at least a detectable pattern of LED flashes to investigate the problem. (There is also a very-long-button-press option, that reflashes the RT1062 with the default Blinky program without any host computer involvement.)

author: peter-h
author_rank: Super Contributor
timestamp: December 20, 2022, 10:12:20 pm
content: QuoteNormally I do like to make a mess for no reasonYour scheme seems to imply that one has two copies of the loader, in different flash blocks, and switches from one to the other. I didn't bother; I just loaded the loader into RAM and it does everything from there. Nice and simple. I posted various threads on RAM based loaders a year or two ago...

author: Siwastaja
author_rank: Super Contributor
timestamp: December 21, 2022, 08:22:52 am
content: Quote from: peter-h on December 20, 2022, 10:12:20 pmRemember the "do not turn power off or your motherboard bricks!!" BIOS updates from early 2000's? Those you applied by booting into DOS, then running the updater tool, fearing you will destroy your computer.The rest of the world went on, for the last 15 or so years every firmware update has been brick-proof. Yes, two copies of the application is all you need. Erase and write one; after verification, mark that one bootable. If that fails, the other app is not touched. Flash is cheap. When was the last time you used more than 50% of the flash for the firmware itself? For me, it was over a decade ago, in a small cost-optimized application on ATTiny25, which used 80-90% of the flash (2K). After that, every project has been way below 50%, so could easily afford split into two apps. All you need is multi-page flash controller, which is also available in almost every MCU, weird budget models like STM32H750 aside.And yes, you are not the only lazy one. I have went with super simple "flasher" code as well in a few projects in past. Just place the functions in RAM, erase and write. Very simple, but comes with window of death. I have minimized this risk by receiving the full firmware in RAM, so there is no communication to fail during flashing. But flash erase is still slow, someone can cut power during that. So we should really stop doing lazy bullshit solutions like this.I remember seeing you having significant trouble with bootloaders. It's true this is more work, of course, but still ain't rocket science. My current project still uses the app itself to write the flash, but it writes theotherapp. Bootloader checks which one has higher counter and valid CRC, and boots that. Still very simple.

author: peter-h
author_rank: Super Contributor
timestamp: December 21, 2022, 11:52:32 am
content: QuoteThis morning.QuoteThat was because I was learning.

author: eutectique
author_rank: Frequent Contributor
timestamp: December 21, 2022, 01:12:01 pm
content: Quote from: Siwastaja on December 21, 2022, 08:22:52 amIs your app position-independent? Or do you build two versions of the app for different VMAs?

author: peter-h
author_rank: Super Contributor
timestamp: December 21, 2022, 02:45:11 pm
content: Oh yes that old oneI did various threads on that. IIRC, nobody had any experience of relocatable code, even though in theory the compiler has a command line option for it.In the case of my loader I compiled it to run at the top 4k of RAM where it gets copied to and then the boot block jumps to it (using some asm code, one of the available hacks to prevent the compiler removing "unreachable" code - that was a whole other bit of fun). The loader itself is 2-3k and that is all that's needed to read data out of some device and program the CPU with it, a block at a time. I do various tests e.g. erase, program 0xaa 0x55 0xff and test the uppermost flash block (which is 128k on the 32f417). The whole device RAM is freely available for whatever purpose. And if that 128k block fails, there is obviously little point in bothering with anything else, but you won't have trashed the existing code (unless it extended into the top 128k). Then I program from top down, and the "boot block" (which is 32k) I program last.If I was developing an SWD loader/debugger I would do the same thing, but I wouldpre-readeach flash address (it is programmed in 32 bit words) and program it only if different. I have put in a pre-read into other parts of my code and itdramaticallyspeeds up programming in any typical development scenario, because most of the time one is doing only small changes and often there is no "position shift" in the code (if e.g. you change int fred=0 to int fred=1, only 1 word changes). I actually don't think ST implemented that in their Cube - SWD - STLINK code.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: December 21, 2022, 03:32:15 pm
content: Quote from: peter-h on December 21, 2022, 11:52:32 amExternal SPI flash is extremely cheap nowadays - that can provide an easy way to download & verify firmware bfore programming. This can be made brick-proof ( and secure if needed) with sufficient though & effort.

author: peter-h
author_rank: Super Contributor
timestamp: December 21, 2022, 04:57:04 pm
content: Indeed, but you are paying money for that privilege. Especially if you have no need for that extra chip.Yet another chip to get shafted on when times are tight, too.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: December 21, 2022, 05:06:49 pm
content: Quote from: peter-h on December 21, 2022, 04:57:04 pmIt's probably cheaper than doubling the size of your onboard flash ( if you even can) for a second image, and there are many manufacturers with pin-compatoble parts

author: Siwastaja
author_rank: Super Contributor
timestamp: December 21, 2022, 07:54:34 pm
content: Quote from: eutectique on December 21, 2022, 01:12:01 pmLink two different versions, all I need is two different linker scripts. Compilation (before linking stage) is the same. Two binaries are produced, of course, so one could consider this a small minus. Doesn't matter to me. One could combine them in one file if that matters.There is a flag in status data stream which tells the updater tool(s) which binary to send (a single bit that indicates "I'm running app_a, please send app_b" or vice versa). The flasher code does one final safety check by looking at the second DWORD in the supplied binary, namely reset vector address, that it indeed is in the address space of the correct binary, before going on with the update. (One could also always send the combined blob to the firmware and it would choose whichever to write. I guess this is the most usual solution.)There also is a CRC added in the binary.

author: ataradov
author_rank: Super Contributor
timestamp: December 21, 2022, 08:01:55 pm
content: Yes, this two images linked at different addresses is the most universal way. Position independent code is next to impossible to achieve. And you really don't need it.

author: Siwastaja
author_rank: Super Contributor
timestamp: December 21, 2022, 08:02:31 pm
content: Quote from: mikeselectricstuff on December 21, 2022, 03:32:15 pmI don't like external SPI flash. Even if "cheap", it's still a BOM item, and completely unnecessary if the target MCU is available with multiple flash pages (and enough flash). This is usually the case.Of course, sometimes it just happens the otherwise good MCU candidate does not have enough flash or multiple pages, and the next better model in the family is way more expensive (or different otherwise) so external flash chip ends up cheaper or better. But it's not that often.Some people offer external flash solutioneven wheninternal multipage flash is available and flash consumption is way below 50%. I don't get this at all, there is absolutely no point. Using external versus internal is always more complicated and more prone to error, IMHO. One has to understand how the MCU flash is used anyway to program it, there's no way around it.

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 21, 2022, 08:08:48 pm
content: Yep. Now a good reason otherwise is just about size. Internal flash is always relatively limited, and it's uncommon to get more than 1MB or 2MB of internal Flash, while you can get cheap external Flash chips with tens of MB.People seem to be wary of wearing out internal Flash by writing to it too often, which could render the code itself compromised. It should not happen if as you say you are careful not to share the same pages for code and data, as internal Flash of MCUs is pretty basic and there is absolutely no internal reordering of data as with SSDs or such, so if you don't touch the "code" area, it shouldn't wear out if you write elsewhere.Now to be fair though, a relatively common point is that the internal Flash of MCUs often has a lower specified max number of write cycles than external Flash chips. That's at least something to look at.

author: Saimoun
author_rank: Frequent Contributor
timestamp: December 21, 2022, 10:23:19 pm
content: Wow - apparently I started quite a topic ha ha!!I started to look at your code @alex - thank you so much for that, it really is a life saverWhat I want to program is a GD32 from another GD32 (probably the same one).As I understood all I have to change is the hal_gpio.h to have the correct GPIO set/clr/out/in/etc, and the target setup in dap_target.c, right?(inhttps://github.com/ataradov/embedded-swd)And for the target I can get inspired of this file, right?https://github.com/ataradov/edbg/blob/master/target_gd_gd32f4xx.cSome of you mentioned halting the CPU of the target MCU (the one that is being programmed). I did not actually think about that but it's a very good point! I can see this is done in the target_select() of target_gd_gd32f4xx.c

author: ataradov
author_rank: Super Contributor
timestamp: December 21, 2022, 10:38:06 pm
content: You can either change hal_gpio.h or just implement your own functions in the dap_config.h using any GPIO manipulation functions you like.Yes, for the target target_gd_gd32f4xx.c would be the closest to what you need. You can look at the edbg target for Atmel Cortex-M0+ devices and see how that translated into the dap_target.c and do similar things to translate stuff in the target_gd_gd32f4xx.c. It shouold not be to hard and you can take it one step at time starting with erase. Once you get that working, the rest is easy.