-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.html
executable file
·883 lines (786 loc) · 47.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 2021-04-13 Tue 15:54 -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bluepill: a GCC/CMake build environment ..</title>
<meta name="generator" content="Org mode">
<meta name="author" content="George Kontsevich">
<meta name="description" content="A GCC/OpenOCD/CMake based setup for building code for the bluepill STM32F1 boards"
>
<link rel="stylesheet" type="text/css" href="../web/worg.css" />
<link rel="shortcut icon" href="../web/panda.svg" type="image/x-icon">
</head>
<body>
<div id="org-div-home-and-up">
<a accesskey="h" href=".."> UP </a>
|
<a accesskey="H" href=".."> HOME </a>
</div><div id="content">
<h1 class="title">Bluepill: a GCC/CMake build environment ..</h1>
<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#orgcd6311f">Intro</a>
<ul>
<li><a href="#orgd394ffe">A Quick start</a></li>
<li><a href="#org5ff19ba">Prior Art</a></li>
</ul>
</li>
<li><a href="#orge3832ae">Anatomy of a build</a>
<ul>
<li><a href="#org88446dd">CMake</a></li>
<li><a href="#orgb52cf13">The Linker Script</a></li>
<li><a href="#org7fc1e56">The Startup File (WIP)</a></li>
<li><a href="#org99b94ff">The STM Libraries</a></li>
<li><a href="#orge725a6e">Our blinky code</a></li>
<li><a href="#org6a2a788">The toolchain</a></li>
</ul>
</li>
<li><a href="#org2ed2810">Getting the code on the chip</a>
<ul>
<li><a href="#org5ebf371">Building</a></li>
<li><a href="#org44e4126">OpenOCD</a></li>
</ul>
</li>
<li><a href="#orgdd11423">Intergrated Development</a>
<ul>
<li><a href="#orgd2f2d60">GDB</a></li>
<li><a href="#org250564f">KDevelop</a>
<ul>
<li><a href="#org3c8d372">Extras</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div id="outline-container-orgcd6311f" class="outline-2">
<h2 id="orgcd6311f">Intro</h2>
<div class="outline-text-2" id="text-orgcd6311f">
<blockquote>
<p>
<b>Note:</b> Since I've written this there have been several efforts to build a complete CMake system. The most complete and impressive one I've seen is <a href="https://github.com/ObKo/stm32-cmake">https://github.com/ObKo/stm32-cmake</a>
</p>
<p>
While this page will still have good info and is educational (esp concerning OpenOCD/GDB) - if you want to do a serious project please take a look at ObKo's template/framework. I've only used it a bit - but it seems very polished and is similar in principle to what I've done. It supports pretty much all STM32 chips so it's not quite as simple as what I've done here
</p>
</blockquote>
<p>
In this guide we will setup a simple minimal blinky for the Bluepill - a very cheap board available from China with the <code>STM32F103C8T6</code> chip on it. They cost a smidge over one dollar each.
</p>
<p>
I will be building a blinky using STM32's Low Level API (explained below). I noticed everyone seems to still be using Make so I've tried to change things up and write up a whole toolchain for this board in CMake so hopefully this guide will provide something new and interesting for some people. At the end I will show how CMake allows us to plug in our project into basically any modern IDE - and we'll get the whole thing running just using GCC and OpenOCD. I have virtually no experience with embedded development, so if there are mistakes or you just want to tell me I'm an idiot, please leave an issue on <a href="https://github.com/geokon-gh/bluepill">the github repo</a>. Note that a big part of the guts of this project are in the submodule which has <a href="https://github.com/geokon-gh/stm32f1-ll/">its own repo</a>
</p>
<div class="figure">
<p><img src="bluepill.jpeg" alt="bluepill.jpeg">
</p>
</div>
<p>
This file and webpage is an org-document and the code within is automatically tangled into the files in the project. I try to note any files I've manually copied from elsewhere
</p>
</div>
<div id="outline-container-orgd394ffe" class="outline-3">
<h3 id="orgd394ffe">A Quick start</h3>
<div class="outline-text-3" id="text-orgd394ffe">
<p>
If you just want to try it out you just need to install <code>cmake</code> <code>gcc-arm-none-eabi</code> and <code>openocd</code>. You will also need a bluepill and a <b>ST-Link V2</b> device. Attach those to your computer and run:
</p>
<pre class="example">
cd your/source/directory
git clone --recurse-submodules https://github.com/geokon-gh/bluepill.git
cd your/build/directory
cmake -DCMAKE_TOOLCHAIN_FILE=your/source/directory/bluepill/toolchain.cmake your/source/directory/bluepill/
make
opeocd
</pre>
</div>
</div>
<div id="outline-container-org5ff19ba" class="outline-3">
<h3 id="org5ff19ba">Prior Art</h3>
<div class="outline-text-3" id="text-org5ff19ba">
<p>
Some (but not all) of the projects from which I took ideas, inspiration and suggestions:
</p>
<ul class="org-ul">
<li><code>dwelch67</code> has some great extremely minimal setups for the blue pilll on <a href="https://github.com/dwelch67/stm32_samples/tree/master/STM32F103C8T6">his github</a>. He describes them extensively in a <a href="https://electronics.stackexchange.com/questions/30736/stm32f2-makefile-linker-script-and-start-up-file-combination-without-commercia">few places on Stack Overflow</a>. Basically here he rolls his own .. everything. It's very greybeard. All the code is in your face - no libraries. Straight writting to registers. Definitely take a look!</li>
<li><code>PurpleAlien</code> has another setup - which is very close to what I'm doing. He described it <a href="https://www.purplealienplanet.com/node/69">on his website</a> and the code is on the <a href="https://github.com/PurpleAlien/stm32-minimal">his github</a>. It's a slightly different chip - but the steps should work almost identically for the <code>bluepill</code>.</li>
<li><code>satoshinm</code> has <a href="https://satoshinm.github.io/blog/171212_stm32_blue_pill_arm_development_board_first_look_bare_metal_programming.html">a wonderful guide</a> where he guides you through all the challenges he had setting up his bluepill. It's long but very informative and I recommend reading it. He also has an accompanying repository where we has code for the blinky working using bare metal, the STM HAL and another 3rd party library. His code (the bare metal part especially) was absolutely invaluable for getting my setup up and running. Check out <a href="https://github.com/satoshinm/pill_blink">his github</a> project.</li>
</ul>
</div>
</div>
</div>
<div id="outline-container-orge3832ae" class="outline-2">
<h2 id="orge3832ae">Anatomy of a build</h2>
<div class="outline-text-2" id="text-orge3832ae">
<p>
Unfortunately getting started and just getting a light blinking involved quite a lot of steps since we have no operating system to handle all the background stuff. I am writing all the piece out here in detail - but please do consider reusing some files from the templates provided by STM. Specifically look in the Cube package in <code>STM32Cube_FW_F1_V1.6.0/Projects/STM32F103RB-Nucleo/Examples_LL/GPIO/GPIO_InfiniteLedToggling</code>. Under <code>SW4STM32</code> you will find a startup script and a linker script. And in <code>Src</code> / <code>Inc</code> you will find additional code files. I will try to mention them in passing.
</p>
</div>
<div id="outline-container-org88446dd" class="outline-3">
<h3 id="org88446dd">CMake</h3>
<div class="outline-text-3" id="text-org88446dd">
<p>
CMake is meta build automation tool. You define your project targets, how you want things linked and built and then it will generate build tools for you. Typically we just generate Make files but it can also coordinate system installation, generate installer wizards for Windows, generate Visual Studio project files and more. CMake has in effect standardized builds into a common set of easy to use terms - so while it's not as flexible as Make and you have to follow a certain layout/pattern, in the end everything ends up cleaner and more reusable and it's hard to shoot yourself in the foot. For us it will be our central tool for coordinating the build and we will define our whole project through a <code>CMakeLists.txt</code> file in our project root. We will see later that actually CMake will give us crucial project meta-information that Clang-tools and IDEs like CLion and KDevelop can hook into it to provide code highlighting/completion and other goodies. All of this is a serious quality-of-life improvement over vanilla Make. Because CMake has become the defacto standard in the C++ world the ecosystem of tools around it just keeps growing year to year.
</p>
<p>
Starting our <code>CMakeLists.txt</code> we write out the usual CMake version and project name
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">cmake_minimum_required</span>(VERSION 3.0)
<span style="color: #0000ff;">project</span>(blinky)
</pre>
</div>
<p>
Our end goal is to create an ELF file that we will flash onto the chip. I suggest adding the <code>.elf</code> extension explicitly to your target name. To keep the template generic enough I just name the elf the same as the project name. So if you fork this project and do your own thing - you can just change the project name and you'll be good to go
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">set</span>(ELF ${<span style="color: #a0522d;">PROJECT_NAME</span>}.elf)
</pre>
</div>
</div>
</div>
<div id="outline-container-orgb52cf13" class="outline-3">
<h3 id="orgb52cf13">The Linker Script</h3>
<div class="outline-text-3" id="text-orgb52cf13">
<p>
When an application normally runs on a desktop machine it's generally running using virtual memory in a virtual application-specific address space. From the applications point of view it can manipulate its own memory however it wants - and it's the operating system that then translates that into safe operations on the actual memory (for instance to insure that the applications don't touch any memory region they shouldn't)
</p>
<p>
On a microcontroller by default there is no operating system to manage the memory and the memory is shared with other functionality - some addresses are reserved for peripherals, other addresses are for interrupts and reset bits, the stack and heap are allocated in some device-specific place and there is also a split between ROM and RAM.
</p>
<p>
Because of these new limitations we can't just start executing code at address zero or drop in a <code>main()</code> function somewhere randomly and start there, we need to tell the linker what the code layout is though a custom <b>linker script</b>. First we tell it which parts correspond to ROM and RAM and what will be their respective sizes. ROM (Read Only Memory) is where the code and constants live, and RAM (Random Access Memory) is where the stack and heap live - the stuff that's dynamic.
</p>
<div class="org-src-container">
<pre class="src src-c">MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
<span style="color: #0000ff;">PROVIDE</span>(_stack = ORIGIN(ram) + LENGTH(ram));
</pre>
</div>
<p>
Even give that, code on a microcontroller doesn't by default start at the first address of ROM and go from there. On a desktop program you generally have an entry point (a <code>main()</code>) and an exit point (ex: <code>exit 0</code>). But a better way to think about the way a microcontroller works is it's as a machine that recieves interrupt signals from external inputs and the chip responds by running code and then returns to whatever it was doing before. These interrupting inputs can be a clock running out, a peripheral wanting attention, an attached debugger wanting to pause everything, etc. There is no real starting point nor an "exit"
</p>
<p>
So instead of a <code>main()</code> or something, the first thing in ROM is a <i>vector table</i> - a table of pointers to the different <b>interrupt handlers</b>. These handlers are the code that is run when each interrupt happens. The first interrupt handler in this table will be special and it's the one that is triggered when the system is powered on, the user presses the reset button, or the code runs out of things to do. It's appropriately called the <b>reset handeler</b>
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #0000ff;">EXTERN</span>(vector_table);
<span style="color: #0000ff;">ENTRY</span>(reset_handler);
</pre>
</div>
<p>
These two are just symbols for the linker - and it will look for them later in the actual code it's linking. So we need to not forget to define them :)
</p>
<p>
Lastly we need to tell the linker that we want those vectors first in the ROM and aligned at the byte level (b/c the micro reads things in byte sized chucks)
</p>
<div class="org-src-container">
<pre class="src src-c">SECTIONS
{
.text : {
*(.vectors)
*(.text*)
. = ALIGN(4);
} >rom
}
</pre>
</div>
<p>
So the chip doesn't need to hunt for the vector table. It's always in the same spot at the start of the ROM - and the reset handler is as well.
</p>
</div>
</div>
<div id="outline-container-org7fc1e56" class="outline-3">
<h3 id="org7fc1e56">The Startup File (WIP)</h3>
<div class="outline-text-3" id="text-org7fc1e56">
<p>
As I mentioned, the reset handler and vector table are just symbols to the linker at this point - so the next step is to write the code for them. The vector table will be set to some default values (and can be changed later) and we'll write the reset handler in a generic way that we can reuse between projects. It will do some initializations and then at the end call to <code>main()</code>. Then when we start a new project we can copy over this file and simply start writing a <code>main()</code> skipping all that initialization. In so doing we've split off these the generic reusable stuff into a separate <b>startup file</b>.
</p>
<blockquote>
<p>
<b>Note:</b> There is nothing special about this file for the compiler or linker - it's just another code file - and you are free to copy it over to your other code files if you want
</p>
</blockquote>
<p>
The code from top to bottom:
</p>
<ul class="org-ul">
<li>We define a reset handler
<ul class="org-ul">
<li>We declare a <code>main()</code> (to be defined in our <code>main.c</code> later)</li>
<li>We initialize some stuff</li>
<li>We call main()</li>
</ul></li>
<li>We define two dummy interrupt handlers.
<ul class="org-ul">
<li>One that spins for ever</li>
<li>One that does nothing and returns</li>
</ul></li>
<li>We define our vector table in detail
<ul class="org-ul">
<li>The first element is the SP (Stack Pointer)</li>
<li>The second element is always the reset handler</li>
<li>After that are the remaining handlers which are being set to basically do nothing</li>
</ul></li>
</ul>
<div class="org-src-container">
<pre class="src src-c"> <span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> <span style="color: #a020f0;">__attribute__</span> ((weak, naked)) <span style="color: #0000ff;">reset_handler</span>(<span style="color: #228b22;">void</span>) {
(*(<span style="color: #a020f0;">volatile</span> <span style="color: #228b22;">unsigned</span> <span style="color: #228b22;">int</span> *)(0x40021018)) |= (1 << 4);
(*(<span style="color: #a020f0;">volatile</span> <span style="color: #228b22;">unsigned</span> <span style="color: #228b22;">int</span> *)(0x40011004)) |= (0x00 << (((13 - 8) * 4) + 2));
(*(<span style="color: #a020f0;">volatile</span> <span style="color: #228b22;">unsigned</span> <span style="color: #228b22;">int</span> *)(0x40011004)) |= (0x02 << ((13 - 8) * 4));
main();
}
<span style="color: #228b22;">void</span> <span style="color: #0000ff;">blocking_handler</span>(<span style="color: #228b22;">void</span>) { <span style="color: #a020f0;">while</span> (1); }
<span style="color: #228b22;">void</span> <span style="color: #0000ff;">null_handler</span>(<span style="color: #228b22;">void</span>) {}
<span style="color: #a020f0;">extern</span> <span style="color: #228b22;">unsigned</span> <span style="color: #a0522d;">_stack</span>;
<span style="color: #a020f0;">__attribute__</span> ((section(<span style="color: #8b2252;">".vectors"</span>)))
<span style="color: #a020f0;">struct</span> {
<span style="color: #228b22;">unsigned</span> <span style="color: #228b22;">int</span> *<span style="color: #a0522d;">initial_sp_value</span>;
<span style="color: #228b22;">void</span> (*reset)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*nmi)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*hard_fault)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*memory_manage_fault)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*bus_fault)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*usage_fault)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*reserved_x001c[4])(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*sv_call)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*debug_monitor)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*reserved_x0034)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*pend_sv)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*systick)(<span style="color: #228b22;">void</span>);
<span style="color: #228b22;">void</span> (*irq[68])(<span style="color: #228b22;">void</span>);
} <span style="color: #a0522d;">vector_table</span> = {
.initial_sp_value = &_stack,
.reset = reset_handler,
.nmi = null_handler,
.hard_fault = blocking_handler,
.sv_call = null_handler,
.pend_sv = null_handler,
.systick = null_handler,
.irq = {
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
null_handler,
}
};
</pre>
</div>
<p>
Now if you open up some startup files in the templates provided by STM you will see that they're all written in assembly and they do a little more than we are doing here. If you squint and look at the assembly you will see that the code is doing basically the same thing + some extra magic - but on a high level it's also defining a reset handler which then calls a main. The remaining interrupt handlers are actually defined in C in <code>stm32f1xx_it.h/c</code> which is next to the source files and headers.
</p>
<p>
Once we have the file we can add it to CMake
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">enable_language</span>(ASM)
<span style="color: #0000ff;">set</span>(STARTUP_FILE <span style="color: #8b2252;">"startup_stm32f103xb.c"</span>)
</pre>
</div>
</div>
</div>
<div id="outline-container-org99b94ff" class="outline-3">
<h3 id="org99b94ff">The STM Libraries</h3>
<div class="outline-text-3" id="text-org99b94ff">
<p>
Next we need actual libraries to write code with - otherwise we are kinda stuck poking at memory addresses with the datasheet. These are all provided in one bundle called <b>Cube</b> and it's on <a href="https://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-mcu-packages/stm32cubef1.html">the STM website</a>. Here is a quick digest of what you get:
</p>
<ul class="org-ul">
<li>The <b>BSP</b> has board specific peripheral libraries.. since we aren't using a board from STM - this really doesn't concern us.</li>
<li>The <b>HAL</b> that comes from STM is the standard <b>Hardware Abstraction Layer</b>. It will be making some simplifying assumptions and do some stuff more automatically for you. I'm going to skip setting this up. Blinking a light should be pretty simple - so I'm shooting to get it working with simpler APIs</li>
<li>Hidden inside of the <b>HAL</b> folder you will see files that are names <code>stm32f1xx_ll_*.c/h</code>. These actually form a seperate sub-library of sorts called the <b>LL</b> API (for <b>Low Level</b>)</li>
<li>The <b>CMSIS</b> ( Cortex Microcontroller Software Interface Standard ) : This library comes from ARM (<i>not STM</i>). It's split into several semi-independent components and provides a common base for all ARM devices (independent of vendor). The <b>HAL</b> and <b>LL API</b> are built on top of the <b>CMSIS</b></li>
</ul>
<p>
Both the <b>HAL</b> and <b>CMSIS</b> need some chip-specific configuration - b/c while the API is standard, under the hood things will change from chip to chip (like memory addresses of things or clock information). I've bundled the <b>LL API</b> and the <b>CMSIS</b> together in a separate project <a href="https://geokon-gh.github.io/stm32f1-ll/index.html">stm32f1-ll</a> (<a href="https://github.com/geokon-gh/stm32f1-ll/">github</a>). It's also building with CMake so we can use it directly in our project (and you can skip registration and downloading the <b>Cube</b> thing). I recommend checking out that project's webpage for more details on how it works - but there is very little magic going on.
</p>
<p>
The library bundle has been added as a submodule to this project, but if you forgot to clone recursively you can clone it right now into the project root with <code>git clone https://github.com/geokon-gh/stm32f1-ll/</code>. Once we have it there we can just add it in
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">add_subdirectory</span>(stm32f1-ll)
</pre>
</div>
<blockquote>
<p>
<b>Note</b>:in <code>STM32Cube_FW_F1_V1.6.0/Middlewares</code> there are additional libraries that sorta live on top of all of this and do more complicated stuff like TCP/IP USB..stuff and Filesystem things. Basically things that are kinda complicated and that you probably want to avoid writing yourself. I'm completely skipping this :)
</p>
</blockquote>
</div>
</div>
<div id="outline-container-orge725a6e" class="outline-3">
<h3 id="orge725a6e">Our blinky code</h3>
<div class="outline-text-3" id="text-orge725a6e">
<p>
Now that we have a linker that can put the code in the right places, and the startup code to initialize things correctly for us we can finally write our blinky code in <code>/src/main.c</code>
</p>
<p>
The libraries/modules in the LL-API are pretty fragmented/decoupled. So while we want to use the GPIO, we also need a few other libraries to get started. The GPIO peripheral for starters need to be powered on by the microcontroller (all the peripherals are powered off by default). The system responsible for that is called <i>Reset and Clock Control</i>, <b>RCC</b> for short. There is another module called <b>BUS</b> which seems to just have helper functions to turn on/off RCC sections.
</p>
<p>
So first we include all three of these modules
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"stm32f1xx_ll_bus.h"</span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"stm32f1xx_ll_rcc.h"</span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"stm32f1xx_ll_gpio.h"</span>
</pre>
</div>
<p>
Then we can start writing our <code>main()</code>
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">void</span>)
{
</pre>
</div>
<p>
We use a BUS module macro to enable the GPIO peripheral. The LED we want to blink on the board is labeled <b>PC13</b>. PC stands for Port C and it's number 13. So we enable GPIO port C. The peripherals controlled by the RCC system are split into two sections APB1 and APB2. GPIO is in the APB2 section.
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #0000ff;">LL_APB2_GRP1_EnableClock</span>(LL_APB2_GRP1_PERIPH_GPIOC);
</pre>
</div>
<p>
We then set this GPIO pin to be an ouput pin and we set it to be a high speed pin
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #0000ff;">LL_GPIO_SetPinMode</span>(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_OUTPUT);
<span style="color: #0000ff;">LL_GPIO_SetPinSpeed</span>(GPIOC, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_HIGH);
</pre>
</div>
<p>
Now that we have the GPIO pin setup we just have an infinite loop that toggles the pin and spends some time sitting in a loop doing nothing
</p>
<div class="org-src-container">
<pre class="src src-c"> <span style="color: #a020f0;">while</span> (1)
{
LL_GPIO_TogglePin(GPIOC, LL_GPIO_PIN_13);
<span style="color: #228b22;">int</span> <span style="color: #a0522d;">i</span> = 200000;<span style="color: #b22222;">/* </span><span style="color: #b22222;">About 1/4 second delay </span><span style="color: #b22222;">*/</span>
<span style="color: #a020f0;">while</span> (i-- > 0) {
<span style="color: #a020f0;">asm</span>(<span style="color: #8b2252;">"nop"</span>);<span style="color: #b22222;">/* </span><span style="color: #b22222;">This stops it optimising code out </span><span style="color: #b22222;">*/</span>
}
}
}
</pre>
</div>
<p>
And that's it!
</p>
<p>
If you look at the GPIO example that comes with the Cube package you will see it does the waiting/spinning in a smarter way using the clock system. But this requires setting up the clock properly and is a bit more complicated. You will also need the <code>system_stm32f1xx.h/c</code> files to configure the clock. For simplicity I've omitted this - but you probably want to add that back in if you're doing more complicated stuff.
</p>
<p>
We can now return to CMake and declare our target elf file and link up our <code>main.c</code> with the startup file.
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">add_executable</span>(${<span style="color: #a0522d;">ELF</span>} ${<span style="color: #a0522d;">STARTUP_FILE</span>}
src/main.c)
<span style="color: #0000ff;">target_include_directories</span>(${<span style="color: #a0522d;">ELF</span>} PUBLIC inc)
</pre>
</div>
<p>
and then we link it to the LL-API library we are using
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">target_link_libraries</span>(${<span style="color: #a0522d;">ELF</span>} ll )
</pre>
</div>
<p>
And I'm also adding in a include directory for future use (it's empty for now)
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">target_include_directories</span>(${<span style="color: #a0522d;">ELF</span>} PUBLIC inc)
</pre>
</div>
</div>
</div>
<div id="outline-container-org6a2a788" class="outline-3">
<h3 id="org6a2a788">The toolchain</h3>
<div class="outline-text-3" id="text-org6a2a788">
<p>
Now that we have all the pieces we just need to tell CMake how we want everything compiled. I'm building using <code>gcc-arm-none-eabi</code> and its associated tools. I did this on a Debian system where this version of gcc can be installed from the repository (name <code>gcc-arm-none-eabi</code>)
</p>
<p>
Canonically the compiler is specified in a separate file so that you can subsitute other possible toolchains (like for instance LLVM or custom versions of GCC). I'll just setup GCC as an example and write it out to a <code>toolchain.cmake</code> file in the source directory
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">set</span>(CMAKE_SYSTEM_NAME Generic) <span style="color: #b22222;"># 'Generic' is used for embedded systems</span>
<span style="color: #0000ff;">set</span>(CMAKE_C_COMPILER arm-none-eabi-gcc)
<span style="color: #0000ff;">set</span>(CMAKE_CXX_COMPILER arm-none-eabi-g++)
<span style="color: #0000ff;">set</span>(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
<span style="color: #b22222;"># tells CMake not to try to link executables during its interal checks</span>
<span style="color: #b22222;"># things are not going to link properly without a linker script</span>
<span style="color: #0000ff;">set</span>(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
<span style="color: #0000ff;">set</span>(CMAKE_OBJCOPY arm-none-eabi-objcopy)
<span style="color: #0000ff;">set</span>(CMAKE_OBJDUMP arm-none-eabi-objdump)
<span style="color: #0000ff;">set</span>(CMAKE_SIZE arm-none-eabi-size)
<span style="color: #0000ff;">set</span>(CMAKE_DEBUGGER arm-none-eabi-gdb)
<span style="color: #0000ff;">set</span>(CMAKE_DEBUGGER arm-none-eabi-gdb)
<span style="color: #0000ff;">set</span>(CMAKE_CPPFILT arm-none-eabi-c++filt)
</pre>
</div>
<p>
If you skip writing a toolchain file then CMake will default to the system compiler and things will start to slowly go wrong for you (kinda unfortunately, it generally doesn't blow up into your face here)
</p>
<p>
Next will also need to tell the linker which linker script to use (which is a bit ugly in CMake)
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">set_target_properties</span>(
${<span style="color: #a0522d;">ELF</span>}
PROPERTIES
LINK_FLAGS
<span style="color: #8b2252;">"-T${</span><span style="color: #a0522d;">PROJECT_SOURCE_DIR</span><span style="color: #8b2252;">}/STM32F103RBTx_FLASH.ld \</span>
<span style="color: #8b2252;"> -mthumb -mcpu=cortex-m3 \</span>
<span style="color: #8b2252;"> -Wl,--gc-sections \</span>
<span style="color: #8b2252;"> -Wl,-Map=${</span><span style="color: #a0522d;">PROJECT_NAME</span><span style="color: #8b2252;">}.map"</span>)
</pre>
</div>
<p>
I'm appending this to the <code>CMakeLists.txt</code>, but it's something that maybe could be in the toolchain file. However b/c it does need the target name (${ELF}) it's more convenient to just append it to the <code>CMakeLists.txt</code> (something to maybe revisit in the future)
</p>
<p>
You'll also notice I added some more linker options - the first two tell the linker it the chip type and the instruction set and the other two:
</p>
<blockquote>
<p>
<b>Note:</b> At first I hadn't given the computer arch/intruction-set flags b/c they're being given to the compiler below and I ended up with a very very subtly big where <code>__libc_init_array address</code> was trying to jump to some addresses right outside of the ROM. It was very bizarre and took me a whole day to track down.
</p>
</blockquote>
<ul class="org-ul">
<li><code>--gc-sections</code> this tells the linker to remove unused code/data from the final executable. There is a pesky <code>_exit()</code> function referrence that will often get slipped into your executable by the compiler. B/c we are running on a microcontroller the code never really exits (it can't quit and hand off executation to an OS after all!) so this exit needs to be removed by the linker. If you leave this off then the linker will get confused and start complaining you never defined an exit function.</li>
<li><code>-Map</code> prints a link map:
<ul class="org-ul">
<li>Where object files and symbols are mapped into memory.</li>
<li>How common symbols are allocated.</li>
<li>All archive members included in the link, with a mention of the symbol which caused the archive member to be brought in.</li>
</ul></li>
</ul>
<p>
The link map is a high-level overview of how your code is placed in memory
</p>
<p>
More linker options are explained in details here: <a href="https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html">https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html</a>
</p>
<p>
We then also need to let the compiler know our target architecture and some compiler options (taken from <a href="https://github.com/PurpleAlien/stm32-minimal/blob/master/Makefile">PurpleAlien</a>)
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">target_compile_options</span>(${<span style="color: #a0522d;">ELF</span>} PUBLIC
-Wall
-g
-std=gnu99
-Os
-mthumb
-mcpu=cortex-m3
-mfloat-abi=soft
-mlittle-endian
-ffunction-sections
-fdata-sections
-Werror
-Wstrict-prototypes
-Warray-bounds
-fno-strict-aliasing
-Wno-unused-const-variable
-specs=nano.specs
-specs=nosys.specs)
</pre>
</div>
<p>
<b>TODO</b> Explain all of these… and again.. would be nice to have in the toolchain file
</p>
</div>
</div>
</div>
<div id="outline-container-org2ed2810" class="outline-2">
<h2 id="org2ed2810">Getting the code on the chip</h2>
<div class="outline-text-2" id="text-org2ed2810">
</div>
<div id="outline-container-org5ebf371" class="outline-3">
<h3 id="org5ebf371">Building</h3>
<div class="outline-text-3" id="text-org5ebf371">
<p>
At this point we have all the files we need to build the code, so just go to a new empty directory and run
</p>
<pre class="example">
cmake -DCMAKE_TOOLCHAIN_FILE=path/to/source/toolchain.cmake /path/to/source/
make
</pre>
<p>
Now in the build directory you'll have some build garbage, the link map <code>blinky.map</code> and <code>blinky.elf</code> - which is the code/executable that we want to get onto the bluepill.
</p>
</div>
</div>
<div id="outline-container-org44e4126" class="outline-3">
<h3 id="org44e4126">OpenOCD</h3>
<div class="outline-text-3" id="text-org44e4126">
<p>
The standard open source software for flashing the bluepill is <b>OpenOCD</b>. On educational/more-expensive boards there will be a secondary chip that helps you flash the microcontroller. But on cheaper and more practical chips this part is omitted (b/c in a sense it's a waste to have the same chip on every single board). So to flash the bluepill you will need something to do the flashing with. I'm using a knock off <code>ST-LINK v2</code> I purchased on Taobao. (note the wiring is in a different order on the board and programmer)
</p>
<div class="figure">
<p><img src="st-link.jpeg" alt="st-link.jpeg">
</p>
</div>
<p>
OpenOCD will provide us with an abstraction layer. It will communicate over JTAG or SWD to the chip and we will communicate with OpenOCD and tell it what we need.
</p>
<p>
OpenOCD's software setup is rather baroque - but the <a href="http://openocd.org/documentation/">documentation</a> is very thorough. You start from the beginning and just read very carefully sequentially and it will all make sense. Fortunately for us - the hardware we're using is very standard so we can use some already provided templates. When I install OpenOCD on my Debian system through <code>apt-get install openocd</code> the templates are in <code>/usr/share/openocd/scripts/board/</code>. After browsing some similar boards (like the stm32f4disovery) you kinda get the picture of how the configuration file should look (<b>THESE VALUES CHANGE BETWEEN POINT RELEASE OF OPENOCD. DOUBLE CHECK THEM IF YOU HAVE ANY ISSUES</b>)
</p>
<p>
The configuration is a bit finicky. For OpenOCD to automatically pick it up it needs to be called <code>openocd.cfg</code> and it needs to be in the directory where you run <code>openocd</code>.
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #228b22;">source</span> [find interface/stlink-v2.cfg]
transport select hla_swd
source [find target/stm32f1x_stlink.cfg]
program blinky.elf verify reset exit
</pre>
</div>
<p>
The finaly file isn't too complicated. It sets the interface type (ie the ST-LINK flashing dongle thing), then it sets the flashing communication protocol for talking to the chip, then the actual chip type and lastly we tell it to program the chip with the <code>.elf</code> we just made. After flashing it will verify the code, reset the controller and then exit OpenOCD
</p>
<p>
For convenience we should also tell CMake to copy this file over to the build directory
</p>
<div class="org-src-container">
<pre class="src src-cmake"><span style="color: #0000ff;">file</span>(COPY
openocd.cfg
DESTINATION
${<span style="color: #a0522d;">CMAKE_BINARY_DIR</span>})
</pre>
</div>
<p>
So now in our build directory we simply run <code>openocd</code> and your program should magically upload to the chip and start running. The light should be flashing at this point :)
</p>
<p>
If it's not, Some things to double check:
</p>
<ul class="org-ul">
<li>The version of OpenOCD you are running… I had weird issues with manually installed OpenOCDs, but the repo one worked great</li>
<li>Check the templates - if you have problems, try some of the other options available</li>
<li>try running OpenOCD as root! Maybe your user doesn't have the right USB permissions or something to that effect</li>
<li>I had weird connection issues that turned out to be due to faulty wires! Thanks to <a href="https://reddit.com/comments/9ba9n8/comment/e53aa2m?context=3">NeoMarxismIsEvil</a> for catching that :)</li>
<li>In the next section about GDB I mention an <code>unlock</code> command.. I'm not 100% sure it's necessary - but try it if you're having issues</li>
</ul>
</div>
</div>
</div>
<div id="outline-container-orgdd11423" class="outline-2">
<h2 id="orgdd11423">Intergrated Development</h2>
<div class="outline-text-2" id="text-orgdd11423">
<p>
One of the big bonuses of using CMake is that it will hook into existing tools very easily.
</p>
</div>
<div id="outline-container-orgd2f2d60" class="outline-3">
<h3 id="orgd2f2d60">GDB</h3>
<div class="outline-text-3" id="text-orgd2f2d60">
<p>
The first basic step is hookin' up a debugger.
</p>
<p>
For some reason Debian (Testing) is missing a <code>arm-none-eabi-gdb</code>, so I had to just download the whole GCC toolchain from <a href="https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads">ARM's website</a> (this only works assuming you're running on a x64 machine). Just whatever you end up using, make sure you don't just run the system GDB! It won't throw you any errors and it will kinda work.. till it doesn't.
</p>
<p>
Once we have the right version of <b>GDB</b> the next part becomes super easy b/c by default <b>OpenOCD</b> will provide us with a GDB server to which we can connect. We just need to disable the part where we flash the program and exit and replace it with a command to reset the chip and wait for GDB
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #228b22;">source</span> [find interface/stlink-v2.cfg]
transport select hla_swd
source [find target/stm32f1x_stlink.cfg]
reset_config srst_nogate
</pre>
</div>
<p>
I honestly didn't entirely understand all the reset configuration options so if you're having issues I'd suggest looking at <a href="http://openocd.org/doc/html/Reset-Configuration.html">the documentation</a> and trying several different settings. I've found the current one works for me. Again, we just run <code>openocd</code> but this time the program kinda hangs and sits and waits for a connection:
</p>
<blockquote>
<p>
$ openocd
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
<a href="http://openocd.org/doc/doxygen/bugs.html">http://openocd.org/doc/doxygen/bugs.html</a>
WARNING: target/stm32f1x<sub>stlink.cfg</sub> is deprecated, please switch to target/stm32f1x.cfg
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 1000 kHz
adapter<sub>nsrst</sub><sub>delay</sub>: 100
none separate
none separate
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : Unable to match requested speed 1000 kHz, using 950 kHz
Info : clock speed 950 kHz
Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 2.913562
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
</p>
</blockquote>
<p>
We open another terminal and run our <code>arm-none-eabi-gdb</code> to bring up the GDB "shell" The next few steps will connect to the OpenOCD server, stop the program running on it, unlock the chip, and load our new program
</p>
<pre class="example">
> target remote localhost:3333
> monitor reset halt
> monitor stm32f1x unlock 0
> load blinky.elf
</pre>
<p>
Now you can set breakpoint, run code, inspect the stack and variables, etc. etc. Look at the GDB manual for all the juicy details - and don't forget about the very handy <a href="https://ftp.gnu.org/old-gnu/Manuals/gdb-5.1.1/html_chapter/gdb_19.html">TUI Mode</a>. Start it with <code>C-x C-a</code>, then hit <code>C-x 2</code> to bring up the assembly. And type <code>s</code> or <code>n</code> to step one line of code at a time and <code>si</code> to step one assembly instruction at a time!
</p>
</div>
</div>
<div id="outline-container-org250564f" class="outline-3">
<h3 id="org250564f">KDevelop</h3>
<div class="outline-text-3" id="text-org250564f">
<p>
To demonstrate how flexible things get thanks to CMake, next I'll show you how to setup KDevelop to run everything for us. In principle this should work equally well with QtCreator or CLion or CQuery/Emacs. You can even hook up linters and other fancy Clang based tools now pretty easily. So this isn't an endorsement of KDevelop over the alternatives b/c after all it's sorta like Visual Studio - a big drop-box driven mess - but I'm just familiar with it and it's quick and easy to get up and running with a CMake project. We'll be able to jump around our code and refactor things in no time. The easiest way to get started is to just get the KDevelop AppImage from <a href="https://www.kdevelop.org/download">their website</a>. Download it, make it executable with <code>chmod +x $KDevelopAppImageFile</code> and run!
</p>
<p>
Next you click <i>Project</i> > <i>Open - Import Project</i> and the navigate to a copy of this repository where the <code>CMakeLists.txt</code> resides. It should automatically give you a window with the project name and with the CMake Project Manager. Just hit <i>Finish</i> on the bottom row and you will get another window to set up your CMake configuration. Here you need:
</p>
<ul class="org-ul">
<li>Select a build directory
<ul class="org-ul">
<li>I typically don't go with the default (b/c my code resides on a USB drive) and I build somewhere else on my main disk. Always using a <code>project_name/build</code> directory encourages people to write sloppy build files that reach into the repository (b/c you can always go <code>../</code> from the <code>/build/</code> folder to get to the repository files). But you shouldnt' write code/configurations that assume their built location ;)</li>
</ul></li>
<li>The installation prefix can be left blank
<ul class="org-ul">
<li>CMake is a bit weird in that it's not just a build tool, but it also has these unnecessary installation features that keep cropping up</li>
</ul></li>
<li>Build Type
<ul class="org-ul">
<li>This part I don't 100% understand at the moment.. but I think you can go with <b>Release</b> here. GDB seems to somehow magically find the matching source code on its own even when you build with no symbols. But if you have issues with debugging don't hesitate to switch to <b>Debug</b></li>
</ul></li>
<li>Provide extra arguments to CMake
<ul class="org-ul">
<li>Here we need to tell CMake about our toolchain. Unfortunately a lot of people don't use toolchain files - as you always always should - and they just go with the random system defaults. KDevelop seems to encourage this further by not providing a field for the toolchain file.. so you need to add a <code>-DCMAKE_TOOLCHAIN_FILE=/path/to/your/project/directory/bluepill/toolchain.cmake</code> in the extra arguments area here (yeah.. this is a bit clunky..)</li>
</ul></li>
</ul>
<p>
Then just hit <i>Run</i> and the wheels should start turning. It will load in your whole project and then index your code + LL/CMSIS libraries for a few minutes. At this point you can already hit <i>Build</i> in the top left and make that <code>elf</code> file like we did from the command line. Infact, underthe hood KDevelop is doing exactly what we did before manually. If you <code>cd</code> to your build directory you can still run <code>make</code> by hand if you want
</p>
<p>
But now we are also getting the benefits of CMake. You can now click on variables, jump around the code and get all the fancy syntax highlighting you expect in a desktop program
</p>
</div>
<div id="outline-container-org3c8d372" class="outline-4">
<h4 id="org3c8d372">Extras</h4>
<div class="outline-text-4" id="text-org3c8d372">
<p>
KDevelop unfortuantely has some very bizarre default working directories in their configurations…
</p>
</div>
<ul class="org-ul">
<li><a id="org63a8786"></a>Execute<br>
<div class="outline-text-5" id="text-org63a8786">
<p>
To make the <i>Execute</i> button flash the program to the chip go to <i>Run</i> > <i>Configure Launches…</i> and then hit <i>+ Add</i> in the top left and select your target's name from the drop down menu (mine is called <code>blinky.elf</code>). In the new screen on the right side, you want to change the <i>Executable</i> from <b>Project Target</b> to <b>Exectuable</b> and then put in <i>the full path</i> to openocd (mine is <code>/usr/bin/openocd</code>). We also need to set the <i>Working Directory</i> to be the build directory so it can find the <code>openocd.cfg</code> file we made. So now when we hit <b>Execute</b> on the top bar it will just run <code>openocd</code> in the build directory. The way we've set things up, this should flash the chip!
</p>
</div>
</li>
<li><a id="org70802c2"></a>Debug (WIP)<br>
<div class="outline-text-5" id="text-org70802c2">
<p>
In that same window you will notice there is a <b>Debug</b> submenu on the left under our target executable. It's probably possible to get the <code>OpenOCD/GDB</code> setup running here as well - but unfortunately here things just got too ugly for me and I couldn't find a sane way to set this up (and I kept having issues where KDevelop wasn't cleaning up the OpenOCD processes correctly). If you find a clean way to get this working then please make an issue/PR and tell me about it :)
</p>
<blockquote>
<p>
This webpage is generated from an org-document (at <code>./index.org</code>) that also generates all the files described.
</p>
<p>
Once opened in Emacs:<br>
</p>
<ul class="org-ul">
<li><code>C-c C-e h h</code> generates the webpage <br></li>
<li><code>C-c C-v C-t</code> exports the code blocks into the appropriate files<br></li>
</ul>
</blockquote>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="postamble" class="status">
<p class="author">Author: George Kontsevich</p>
<p class="date">Created: 2021-04-13 Tue 15:54</p>
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
</body>
</html>