summaryrefslogtreecommitdiffstats
path: root/_site/archive/arduino-due/index.html
blob: e8c167924d7b2ee21a718c83ed6a55c419ad1ae2 (plain)
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
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Bare-metal ARM Cortex M3 chips</title>

    <head>
<meta charset="utf-8">
  <title>Bare-metal ARM Cortex M3 chips</title>
  <link rel="stylesheet" href="/assets/css/main.css">
  <link rel="stylesheet" href="/assets/css/normalize.css">
  <link rel="stylesheet" href="/assets/css/skeleton.css">
</head>



  </head>
  <body>

    <div class="container">
  <ul id="navlist" class="left">
    
    <li >
      <a href="/">hme</a>
    </li>
    <li class="active">
      <a href="/archive/">arc</a>
    </li>
    <li >
      <a href="/projects/">pjt</a>
    </li>
    <li >
      <a href="/about/">abt</a>
    </li>
    <li><a href="/feed.xml">rss</a></li>
  </ul>
</div>



    <main>
      <div class="container">
        <h2 class="center" id="title">BARE-METAL ARM CORTEX M3 CHIPS</h2>
        <h6 class="center">05 OCTOBER 2024</h5>
        <br>
        <div class="threecol justify"><p>This post is about programming bare metal SAM3X8E Arm Cortex M3 chips found on
Arduino Due boards. I had to learn how to do this because none of the
high-level tools for programming Arduino Dues are available for OpenBSD, which
I use for much of my personal computing.</p>

<h2 id="toolchain">Toolchain</h2>

<p>Since we will not be using pre-packaged development tools, we need to assemble
our own toolchain. As usual, we need a compiler toolchain to build programs for
the target chip. As we will be bypassing the embedded bootloader, we will also
need a hardware programmer and an on-chip debugger to flash programs to the
chip. I used the following toolchain.</p>

<ul>
  <li><a href="https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain" class="external" target="_blank" rel="noopener noreferrer">Arm GNU compiler 
toolchain</a>.</li>
  <li><a href="https://openocd.org/" class="external" target="_blank" rel="noopener noreferrer">OpenOCD</a> on-chip debugger.</li>
  <li><a href="https://www.st.com/en/development-tools/st-link-v2.html" class="external" target="_blank" rel="noopener noreferrer">ST-LINK/V2</a>
programmer.</li>
</ul>

<h2 id="electrical-connections">Electrical connections</h2>

<p>The following diagram outlines the electrical connections between the different
components necessary to move a compiled program from a PC to the MCU.</p>

<table style="border: none; width: 100%;">
  <tr style="border: none;">
    <td style="border: none; width: 50%; vertical-align: top; background-color: transparent;">
      <img src="schematic.png" alt="Pinout" style="width: 100%" />
      <p style="text-align: center;">Wiring</p>
    </td>
    <td style="border: none; width: 50%; vertical-align: top; background-color: transparent;">
      <img src="connections.jpeg" alt="Circuit" style="width: 100%" />
      <p style="text-align: center;">Arduino Due</p>
    </td>
  </tr>
</table>

<p>Arduino Due exposes the SAM3X8E’s Serial Wire Debug (SWD) interface via its
DEBUG port. The ST-LINK/v2 programmer uses the SWD protocol to communicate with
the chip.</p>

<h2 id="uploading-the-program">Uploading the program</h2>

<p>Follow the steps below to upload a program to the SAM3X8E chip. The
source.tar.gz tarball at the end of the page contains a sample program with a
OpenOCD config file and a linker script.</p>

<ol>
  <li>Start OpenOCD:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ openocd -f openocd-due.cfg
</code></pre></div>    </div>
  </li>
  <li>
    <p>Open a telnet session and check that the GPNVM1 bit is set. Otherwise
set it to 1:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ telnet localhost 4444
  &gt; halt
  &gt; at91sam3 gpnvm show
  &gt; at91sam3 gpnvm set 1
  &gt; at91sam3 gpnvm show
</code></pre></div>    </div>
  </li>
  <li>Build the program using the custom linker script.
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -T script.ld \
    -nostartfiles \
    -nostdlib \
    -o a.elf main.c
</code></pre></div>    </div>
  </li>
  <li>Upload the program using OpenOCD:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ openocd -f openocd-due.cfg -c "program a.elf verify reset exit"
</code></pre></div>    </div>
  </li>
</ol>

<p>Refer to the OpenOCD manual (AT91SAM3 flash driver section) for a complete list
of commands supported for the ATSAM3X8E.</p>

<h2 id="gpnvm-bits-and-the-linker-script">GPNVM bits and the linker script</h2>

<p>By design, ARM chips boot into address 0x00000. ATSAM3X8E’s memory consists of
a ROM and a dual-banked flash (flash0 and flash1), residing in different
locations of the chip’s address space.</p>

<p>The GPNVM bits control which of them maps to 0x00000. When GPNVM1 is cleared
(default), the chip boots from the ROM, which contains Atmel’s SAM-BA
bootloader. So, the chip runs the embedded bootloader instead of our program.</p>

<p>When the GPNVM1 bit is 1 (and the GPNVM2 bit is 0), flash0 at address 0x80000
maps to 0x00000. When both GPNVM bits are 0, flash1 maps to 0x00000. Since we
place our program in flash0 using the linker script, we set the GPNVM1 bit and
leave the GPNVM2 bit as it is.</p>

<p>The linker script places the vector table at the first address of the flash.
ARM chips expect this unless we relocate the vector table using the VTOR
register. The first entry of the vector table must be the stack pointer, and
the second must be the reset vector.</p>

<p>Finally, the ATSAM3X8E uses a descending stack. So, in the linker script, we
initialize the stack pointer to the highest memory location available. In the
reset vector, we zero out memory, initialize registers, and perform other tasks
before passing control to the main program.</p>

<p>Files: <a href="source.tar.gz">source.tar.gz</a></p>
</div>
        <p class="post-author right italics">by W. D. Sadeep Madurange</p>
      </div>
    </main>

  </body>
</html>