Jekyll2023-08-27T18:58:55+00:00/feed.xmlDuct Tape, Bubble Gum, and SolderA personal website that collects my projects, musings, and miscellany side projects into a semi-coherent collection.Bluetooth Low Energy and Reversing a Smart Lightbulb2021-09-22T00:00:00+00:002021-09-22T00:00:00+00:00/blog/2021/9/22/using-adafruits-bluetooth-sniffer<p>“Smart” things are the wave of the future! Everyone wants some bit of tech that already exists, like a lightbulb, but now controlled through an app! Or at least, that’s what marketers have decided on. But sometimes the companies maintaining the app goes under, or decides to not support what you bought anymore, and your fancy smart lightbulb becomes, well, a $35 lightbulb.</p>
<p>I recently got my hands on an old <a href="https://www.amazon.com/gp/product/B00Y6X93EQ/ref=ppx_yo_dt_b_asin_title_o05_s00?ie=UTF8&psc=1">bluetooth lightbulb</a> that was first made in 2015. But the phone app to control it is clunky and ugly, and hasn’t been updated since 2018. So if I want to still use it now, the options are to have an unmaintaned, potential security-risk app on my phone, or not use it. <em>Or</em>, be me, since I’ve been itching to learn more about bluetooth low energy. In which case, it becomes time to do some reverse engineering!</p>
<p><img src="/assets/bluetooth-sniffing/excerpt_image.png" alt="Wireshark and phone app next to each other" /></p>
<!--more-->
<h2 id="the-plan">The Plan</h2>
<p>Use the <a href="https://www.adafruit.com/product/2269">adafruit bluetooth LE sniffer</a> to watch communication between the app and the lightbulb, and see if I can figure out how to turn it on/off, change the color, and set timers.</p>
<h2 id="intro-to-bluetooth-low-energy">Intro to Bluetooth Low Energy</h2>
<p>First, the bluetooth light will advertise itself using Generic Access Profile, aka GAP, until an app or what have you connects to it. I’m not going to go into that right now, because for reverse engineering, I know it connects, I want to know what it does once it’s connected. That means I need to focus on a different protocol, Generic Attribute Profile, aka GATT.</p>
<p>Once a bluetooth low energy thing is connected to the app that controls it, it switches to using GATT to communicate. GATT is what allows you to interact with the lightbulb (or other peripheral device). You can read data from the lightbulb (e.g. what color it is right now), or send data (e.g. setting the color, setting the timer).</p>
<p>For GATT there are three concepts that are the most important: profiles, services, and characteristics. Profiles are collections of services, and services have a collection of characteristics. Characteristics are basically just key/value pairs that let you read and write data to the connected device. Services collect related characteristics (e.g. color control characteristics would all be grouped in a color service). Profiles are an abstract collection of services, not on a device itself. Services and characteristics ARE on the device.</p>
<p>Let’s do a made-up example of those three concepts. Say I want to make a Lightbulb Profile. Profiles are conceptual collections of services. For this lighbulb profile, I want to have two different services. One service is the Light service, which will control the light color and on/off state. The other service is the timer service. That’ll control what timers a user sets (e.g. have the light turn on at 9am). The Light service will probably need to read and write the current hex color of the lightbulb, so it’ll need a characteristic with a value of the current hex color, and permissions to both read and write. It’ll also need a second characteristic, maybe just called the power characteristic, and the value is 1 or 0, depending on if it’s on or off. I’d also set that to be both read and write, so I could see if the light is turned on, and if not, set it to on.</p>
<p>The Timer service will also have a collection of characteristics that will let it view current timers on the device, add/delete timers, etc.</p>
<p>Here’s a diagram of the above example, to give you another view. Note if you connected to the lightbulb, you wouldn’t see the profile info, just the services and characteristics.</p>
<p><img src="/assets/bluetooth-sniffing/bluetooth_LightProfile_Example.png" alt="Drawn diagram of above example" /></p>
<blockquote>
<p><strong>NOTE</strong> this is not how the actual lightbulb I’m using is setup, this is just an example of a way to structure a bluetooth LE device to get the concepts in your head</p>
</blockquote>
<p>There’s one final bit that is used a lot: the characteristic descriptor. This is attached to a characteristic, and is basically metadata about the characteristic. So for the earlier Lightbulb profile, I can create a characteristic descriptor that is attached to the Color characteristic, and set the descriptor to have a value of “the color of the light in hex”. This helps me if I’m troubleshooting an app to talk with the lightbulb, or when I’m reverse engineering.</p>
<p>The conceptual model I currently have is something like this:</p>
<p><img src="/assets/bluetooth-sniffing/bluetooth_UML_Style_Explanation.png" alt="Simple diagram with boxes connected with lines. Profiles, services, characteristics, and characteristic descriptors are each a seperate box with a line between each" /></p>
<p>The little “+” on the line indicates that the box above it can have one or more. So a profile can have one or more services in it. The “*” means it can have zero or one. So the Characteristics can have zero or more characteristic descriptors. The words tabbed in are individual fields. So Characteristics have permissions and a value.</p>
<p>However, that’s the conceptual idea, not the implementation. In a more in-depth way, GATT is a big table. Each row has a handle to reference it, kind of like a key in a key/value pair. Then there’s a type, which is a UUID that either matches up with the <a href="https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf">16-bit UUID Numbers Document</a> or is custom. Then permissions (READ, WRITE, NOTIFY), and lastly, some sort of value, which depends on the type of that row. Yes, that’s pretty of confusing.</p>
<blockquote>
<p><strong>NOTE</strong> That <a href="https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf">16-bit UUID Numbers Document</a> is really important. It lists all bluetooth-defined UUIDs. These UUIDs are used all over the place to identify the type of row each row in the GATT table is, types of characteristics and descriptors, etc.</p>
</blockquote>
<p>Remember that conceptual model? That maps to this table, I’ll walk you through making your own GATT table. Since the profiles are abstract, we can just ignore them for now. So first, we have to declare we have a service. We do this by creating a handle (in my example below, 0x001), setting the type as “Service Declaration”, permission to read only, and then the value as a UUID that says what sort of service it is. Bluetooth has a lot of declared “GATT Service Type” UUIDs in the document I linked above, you can browse them if you want.</p>
<p>Now that a service has been declared, lets declare some characteristics. Instead of having a single row where the “value” column is the value of the characteristic, we first have to do a Characteristic Declaration, like we did the service. So that gets its own handle, the type is “Characteristic Declaration”, it’s read only, and the value has several bits of info:</p>
<ul>
<li>the handle of the characteristic value (I’ll get to that next)</li>
<li>the type of characteristic it is</li>
<li>the permissions for this characteristic (e.g. if it’s WRITE or READ only).</li>
</ul>
<p>The type of characteristic is one of the “GATT Characteristic and Object Type” UUIDs in the bluetooth doc linked above, <em>OR</em> a custom UUID that the devs decide on.</p>
<p>Once we have have the Characteristic <em>declaration</em> we can add a row talking about the Characteristic’s <em>value</em>. It gets a handle, type, and permission that all have to match what the Characteristic Declaration said it would have. Finally, the value field for this row is the actual value set by the peripheral. So if this characteristic lets me read the hex color the light is currently set to, the value would be some hex value like <code class="language-plaintext highlighter-rouge">64ff32</code>.</p>
<p>And lastly, Characteristic Descriptors! These don’t get a declaration and then a value row like Characteristics, instead they’re just a single row after the Characteristic Value row. They get a handle, the type is one of the “GATT Descriptor” UUIDs from the bluetooth doc, or a custom one set by a dev, permissions (what permissions depends on the type), and lastly a value. A common descriptor is the “Characteristic User Description Descriptor”, which is UUID 0x2901. The value for this descriptor is a user-readable description for the given descriptor. So for the example characteristic above, a characteristic description descriptor would have a value of “Hex value of light” or something.</p>
<p>Here’s the table I described above, but in actual table-form:</p>
<table>
<thead>
<tr>
<th>Handle</th>
<th>Type (defined by UUID)</th>
<th>Permissions</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x001</td>
<td>Service declaration UUID (0x2800 for primary services, 0x2801 for secondary)</td>
<td>read only</td>
<td>UUID that matches the “GATT Service type” UUIDs from Bluetooth, or custom value</td>
</tr>
<tr>
<td>0x002</td>
<td>Characteristic Declaration UUID (0x2803)</td>
<td>read only</td>
<td>This characteristic value’s: handle (in this case 0x003), type (one of the “GATT Characteristic and Object Type” UUIDs from bluetooth, or custom), permissions</td>
</tr>
<tr>
<td>0x003</td>
<td>type declared by 0x002</td>
<td>permissions declared by 0x002</td>
<td>some value set by the peripheral</td>
</tr>
<tr>
<td>0x004</td>
<td>Characteristic Descriptor (one of the “GATT Descriptor” UUIDs from bluetooth or custom)</td>
<td>depends on descriptor type</td>
<td>some sort of value, e.g. “Hex value of light”</td>
</tr>
</tbody>
</table>
<p>Oof that’s a lot of theory and examples, let’s get back to what I wanted to do in the first place, poke around at a lightbulb.</p>
<h2 id="exploring-the-lightbulb">Exploring the Lightbulb</h2>
<p>Now that I have some idea what I’m looking at, let’s start looking at the lightbulb. There’s several apps that help troubleshoot and look at bluetooth LE connections, I used the <a href="https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp&hl=en">nordic smartphone app for android</a>. That gave me some basic lightbulb info:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Name: LEDBlue-8B109BEB
Address: 50:33:8B:10:9B:EB
RSSI: -46
Last advertisement packet:
Raw data: 0x0201060702F0FFE5FFE0FF12094C4544426C75652D384231303942454220051210001400020A04
</code></pre></div></div>
<p>The Address info is important because that is how it’ll appear in wireshark! Let’s explore some of the services and characteristics the lightbulb is advertising, to give some hints for when we start sniffing.</p>
<p><img src="/assets/bluetooth-sniffing/Screenshot_nordicApp_ServicesList.png" alt="Screenshot of the nordic app displaying list of services for the lightbulb" /></p>
<p>It has several standard services that are designed by bluetooth, the Generic Access, Generic Attribute and Device Information Service. Poking around at them, though, it looks like the characteristics in those services are mostly set to default values, or not set at all. It also has the following Unknown UUID services:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0000fff0-0000-1000-8000-00805f9b34fb
0000ffe5-0000-1000-8000-00805f9b34fb
0000ffe0-0000-1000-8000-00805f9b34fb
</code></pre></div></div>
<p>The format of the UUIDs follow the bluetooth standard (0000XXXX-0000-1000-8000-00805f9b34fb where XXXX is a unique value), but I looked up the services on bluetooth’s <a href="https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf">16-bit UUID Numbers Document</a> and didn’t find anything. So presumably these are custom services designed by the company that made the lightbulb.</p>
<p>I poked around in the different services, and the 0xFFE5 service seems the most promising for controlling light colors. It has several characteristics with descripters that say “Green” or “Red” or “RGBW 4 bytes”. The individual colors have <code class="language-plaintext highlighter-rouge">READ, WRITE</code> permissions, but the RGBW characteristic is <code class="language-plaintext highlighter-rouge">WRITE NO RESPONSE</code>, which is interesting to note.</p>
<p><img src="/assets/bluetooth-sniffing/Screenshot_nordicApp_CharacteristicDescriptionOfColors.png" alt="Screenshot of nordic app displaying some of the characteristics of the 0xFFE5 service. The Characteristic User Descriptions have value of "Blue" or "Green" or "RGBW 4 bytes"" /></p>
<p>The other unknown services are not has helpful, and most of the characteristics have generic “Characteristic 2” descriptors attached to them. Apparently the devs got tired of giving useful descriptions at this point?</p>
<p><img src="/assets/bluetooth-sniffing/Screenshot_nordicApp_CharDescGenericDesc.png" alt="Screenshot of nordic app displaying characteristics with descriptions like "Characteristic 1" or "Characteristic 2"" /></p>
<p>I think this is about the limit of interesting things I can do just looking at the nordic app. Let’s switch to sniffing!</p>
<h2 id="setting-up-the-sniffer">Setting up the Sniffer</h2>
<p>Once again, Adafruit has a <a href="https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-sniffer/using-with-sniffer-v2">nice writeup</a> on the setup for the bluetooth sniffer.</p>
<p>The basic steps I did was:</p>
<ol>
<li>downloaded extcap folder from adafruit</li>
<li>copied into my extcap folder for wireshark, which for me was at: /usr/lib/x86_64-linux-gnu/wireshark/extcap</li>
<li>ran <code class="language-plaintext highlighter-rouge">python --version</code> to make sure it was 2.7</li>
<li>tested by going to the extcap directory in terminal and running <code class="language-plaintext highlighter-rouge">python nrf_sniffer.py</code></li>
<li>ran <code class="language-plaintext highlighter-rouge">sudo pip2 install pyserial</code> to get rid of serial error</li>
<li>tested again and got “No arguments given!” which indicates it’s running right</li>
</ol>
<p>Once the initial setup was done, I closed wireshark, plugged in the sniffer, re-opened wireshark, and found the sniffer listed as “nrf-Sniffer” in the list of local interfaces on wireshark. But when I double clicked to run, I got the error: “Couldn’t run /usr/bin/dumpcap in child process: Permission denied”. Turns out my account wasn’t included in the <code class="language-plaintext highlighter-rouge">wireshark</code> group, so I had to update it by running <code class="language-plaintext highlighter-rouge">sudo usermod -a -G wireshark danielle</code>. Once I logged off and then logged on again it worked. I was sniffing packets!</p>
<blockquote>
<p><strong>NOTE</strong> Nordic semiconductor has a user guide that adafruit saved a copy of, it’s worth a read: <a href="https://cdn-learn.adafruit.com/assets/assets/000/059/041/original/nRF_Sniffer_User_Guide_v2.1.pdf?1533935335">https://cdn-learn.adafruit.com/assets/assets/000/059/041/original/nRF_Sniffer_User_Guide_v2.1.pdf?1533935335</a></p>
</blockquote>
<h2 id="sniffing-packets">Sniffing Packets</h2>
<p>During the initial sniffing to see what’s up, I was really frustrated by something so I want to highlight it right away. The sniffer is not guarenteed to catch every packet on the air. So sometimes, it will miss the connection request from the phone to the lightbulb. This means it can’t track that connection, and wireshark wont display any packets after the phone is connected, even if it’s sending lots of data back and forth. If you connect to the lightbulb (or other bluetooth LE device) and wireshark stops tracking it, close the app on your phone, wait for the lightbulb to start advertising again, and try to connect again.</p>
<h3 id="following-one-device">Following One Device</h3>
<p>Once the wireshark session is started, you’ll probably be slammed with a bunch of advertising packets from every peripheral device that isn’t currently connected. The nordic add-on for wireshark has a drop down labeled “Device”, which lists the Mac address of all advertising addresses. Select the lightbulb <code class="language-plaintext highlighter-rouge">50:33:8B:10:9B:EB</code> and it’ll only display those packets.</p>
<p><img src="/assets/bluetooth-sniffing/wireshark_advertising_packets.png" alt="Screenshot of wireshark displaying captured packets" /></p>
<p>So now it only displays the lightbulb’s packets, but there’s still a lot to read through. Let’s start using some filters.</p>
<h3 id="parsing-a-capture">Parsing a capture</h3>
<p>Like I said earlier, I don’t care about the advertising and connecting process. I can’t imagine a lightbulb would have a non-standard connection, so I’m just going to ignore it for now. Wireshark lets you filter out packets by writing statements in the “Apply a display filter” textbox at the top. To use a filter to remove advertising packets, type in <code class="language-plaintext highlighter-rouge">!btle.advertising_address</code> and hit enter.</p>
<p>This makes it a bit more readable, but still has packets with protocol “LE LL”, which stands for bluetooth Low Energy Link Layer. This is responsible for advertising, scanning, and creating/maintaining connections, and other protocols rely on it. So again, I don’t think I care about this layer. In fact, I really care about the GATT stuff, so lets only display that. The display filter for that is just <code class="language-plaintext highlighter-rouge">btatt</code>.</p>
<p><img src="/assets/bluetooth-sniffing/wireshark_btattFilter.png" alt="Screenshot of wireshark displaying packets after they've been filtered by the btatt filter. There are multiple "Find information request" lines in the info column, as well as "Sent Write Command"" /></p>
<blockquote>
<p><strong>NOTE</strong> The Source column switches to “Master”/”Slave” terminology automatically. The “Master” is phone, “the slave” is the lightbulb. I’m not sure how to change that text to a more descriptive option like “Central” and “peripheral” or “client” and “server”, unfortunately.</p>
</blockquote>
<p>This is a more manageable list. Poking around, we can see initially the phone is sending info requests about different services and characteristics. Then, right at the end of the capture, there’s a bunch of “sent write command” to the <code class="language-plaintext highlighter-rouge">0x002e</code> handle. Changing the filter to <code class="language-plaintext highlighter-rouge">btatt.opcode == 0x52</code> filters the <code class="language-plaintext highlighter-rouge">ATT</code> packets down to just the ones sending write commands. The info column gives me the handle it’s writing to, but not the value it’s sending. I can add the value as a column by opening up the packet in the bottom window (aka click on a write packet), right-click on the value, and select “apply as column”.</p>
<p><img src="/assets/bluetooth-sniffing/wireshark_writePackets_withValueColumn.png" alt="Screenshot of wireshark with filter, and new "value" column. The first two packets have random looking values, and after that all values follow a simple looking pattern" /></p>
<blockquote>
<p><strong>NOTE</strong> I did some cheating on the screenshots, and they’re actually from the capture when I did my testing below. So if you notice any patterns already, pretend you didn’t yet, I’ll talk more about that in the next section!</p>
</blockquote>
<p>Now that I’ve poked around some, let’s do some testing.</p>
<h3 id="hypothesis-and-testing">Hypothesis and Testing</h3>
<p>The first thing I want to figure out is something I would think is the simplest: setting the color of the lightbulb. The lightbulb app lets you set the color by selecting a point on a color wheel and set brightness with a slider bar at the bottom of the screen. The RGB of the color you select is displayed in the upper left. You can also save up to 5 specific color/brightness settings and switch to them with a touch of a button. Here’s a screenshot:</p>
<p><img src="/assets/bluetooth-sniffing/Screenshot_magicLight_ColorPicker.png" alt="Screenshot of app as described above" /></p>
<p>So, <strong>my hypothesis</strong>: It’s probably sending color data via either RGB or Hex. To easiser find those packets, I can save specific colors, varying the color and brightness, and then sniff the connection while repeatedly cycling through my saved colors.</p>
<p>Here’s the color options I saved, their RGB, Hex, and Brightness values:</p>
<table>
<thead>
<tr>
<th> </th>
<th>RGB</th>
<th>Hex</th>
<th>Brightness</th>
</tr>
</thead>
<tbody>
<tr>
<td>option one</td>
<td>100, 255, 50</td>
<td>64ff32</td>
<td>100%</td>
</tr>
<tr>
<td>option two</td>
<td>255, 101, 53</td>
<td>ff6535</td>
<td>100%</td>
</tr>
<tr>
<td>option three</td>
<td>102, 51, 255</td>
<td>6633ff</td>
<td>100%</td>
</tr>
<tr>
<td>option four</td>
<td>51, 25, 128</td>
<td>331980</td>
<td>50%</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>NOTE</strong>: I made option 3, then set the brightness to 50% and then set that as option four. So it should have had the same RGB values. Since it didn’t, that must mean the app code changed the RGB value based on brightness. So brightness may just be a function of RGB and not a separate variable at all.</p>
</blockquote>
<p>With that set, I disconnected from the lightbulb, started a wireshark session, connected, and cycled through the saved colors I just added, going through them in order 3 times.</p>
<p>I stopped the capture and did the filtering I talked about above. Looking at the write commands to the <code class="language-plaintext highlighter-rouge">0x02e</code> handle, and just the values sent, I see a pattern:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Value
5664ff3200f0aa
56ff653500f0aa
566633ff00f0aa
5633198000f0aa
5664ff3200f0aa
56ff653500f0aa
566633ff00f0aa
5633198000f0aa
5664ff3200f0aa
56ff653500f0aa
566633ff00f0aa
5633198000f0aa
</code></pre></div></div>
<p>All values start with 56 and end with 00f0aa. I cycled through the 4 options three times in a row, and I can see these values repeating three times. Well <em>that</em> seems awfully suspicious…</p>
<h3 id="sending-custom-commands">Sending Custom Commands</h3>
<p>As it turns out, my laptop already has all the hardware and software needed to send custom bluetooth LE packets! It’s a linux box, and already has bluez on it, as well as gattool, hciconfig, and hcitool. If you also have a linux box but not the tools yet, Jared Wolf has a blog post about how to install and set them up: <a href="https://www.jaredwolff.com/get-started-with-bluetooth-low-energy/">https://www.jaredwolff.com/get-started-with-bluetooth-low-energy/</a>.</p>
<p>If you don’t have a linux box, Adafruit does have a tutorial on how to install the bluez stack on a raspberry pi here: <a href="https://learn.adafruit.com/pibeacon-ibeacon-with-a-raspberry-pi/compiling-bluez">https://learn.adafruit.com/pibeacon-ibeacon-with-a-raspberry-pi/compiling-bluez</a>.</p>
<p>Basic steps for use:</p>
<ol>
<li>Make sure bluetooth is turned on on computer! In my case, I go to where I set the wifi and make sure the little bluetooth symbol has the word “On” next to it.</li>
<li>In terminal, run <code class="language-plaintext highlighter-rouge">hcitool dev</code>, which shows any bluetooth hardware connected to my laptop, and it’s status. I took a screenshot of running this command when the bluetooth is turned off, then turned on, to see the difference:
<img src="/assets/bluetooth-sniffing/terminal_hcitoolDev_bluetoothOffAndOn.png" alt="Screenshot of terminal" /></li>
<li>Running <code class="language-plaintext highlighter-rouge">sudo hcitool lescan</code> does a low energy scan with the default bluetooth device (my laptop’s <code class="language-plaintext highlighter-rouge">hci0</code> device) and shows the IDs of any broadcasting peripherals. I spotted the <code class="language-plaintext highlighter-rouge">50:33:8B:10:9B:EB</code> device so I know my laptop is within range.
<blockquote>
<p><strong>NOTE</strong> if <code class="language-plaintext highlighter-rouge">sudo hcitool lescan</code> doesn’t return anything, you may have to turn off bluetooth and turn it back on again. I had that happen a couple times and it was unclear why that happened.</p>
</blockquote>
</li>
<li>Run <code class="language-plaintext highlighter-rouge">sudo gatttool -I</code> to start an interactive gatttool instance, and then enter <code class="language-plaintext highlighter-rouge">connect 50:33:8B:10:9B:EB</code> to connect and start interactive session with lightbulb. For help with gatttool, type <code class="language-plaintext highlighter-rouge">help</code></li>
</ol>
<p>Using the gatt tool’s <code class="language-plaintext highlighter-rouge">characteristics</code> command I get a list of all characteristics and their UUIDs. The nordic app listed the RGBW 4bytes characteristic as a UUID of 0xFFE9. The <code class="language-plaintext highlighter-rouge">characteristics</code> command gives this line with that UUID:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>handle: 0x002d, char properties: 0x04, char value handle: 0x002e, uuid: 0000ffe9-0000-1000-8000-00805f9b34fb
</code></pre></div></div>
<p>This means the characteristic value’s handle is 0x002e, and it’s the one I’d want to write to if I want to update the RGBW 4bytes characteristic. It also matches up nicely with wireshark’s packet capture. So the lightbulb is sending data to the RGBW 4byte characteristic! This further supports my “it’s sending hex to update the color” hypothesis.</p>
<p>If I only had the wireshark data, I could also work backwards to find out the characteristic it’s writing to. Running <code class="language-plaintext highlighter-rouge">primary</code> gives me a list of primary services, and the range of handles for each. Looking at that I can see the <code class="language-plaintext highlighter-rouge">0xffe5</code> service has handles <code class="language-plaintext highlighter-rouge">0x0023</code> to <code class="language-plaintext highlighter-rouge">0x0033</code>, so the <code class="language-plaintext highlighter-rouge">0x002e</code> handle is in that service. Relevant line:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>attr handle: 0x0023, end grp handle: 0x0033 uuid: 0000ffe5-0000-1000-8000-00805f9b34fb
</code></pre></div></div>
<p>So I can then run <code class="language-plaintext highlighter-rouge">characteristics 0x0023 0x0033</code> and see all characteristics:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>handle: 0x0024, char properties: 0x0a, char value handle: 0x0025, uuid: 0000ffe6-0000-1000-8000-00805f9b34fb
handle: 0x0027, char properties: 0x0a, char value handle: 0x0028, uuid: 0000ffe7-0000-1000-8000-00805f9b34fb
handle: 0x002a, char properties: 0x0a, char value handle: 0x002b, uuid: 0000ffe8-0000-1000-8000-00805f9b34fb
handle: 0x002d, char properties: 0x04, char value handle: 0x002e, uuid: 0000ffe9-0000-1000-8000-00805f9b34fb
handle: 0x0030, char properties: 0x0a, char value handle: 0x0031, uuid: 0000ffea-0000-1000-8000-00805f9b34fb
</code></pre></div></div>
<p>And I can see the characteristic value handle of 0x002e is for characteristic with handle 0x002d! I can also see that the next characteristic’s handle is <code class="language-plaintext highlighter-rouge">0x0030</code>, not <code class="language-plaintext highlighter-rouge">0x002f</code>. Handles don’t have to be consecutive, but this may mean there’s a characteristic descriptor after the characteristic value. I can search for this by doing <code class="language-plaintext highlighter-rouge">char-desc 0x002e 0x0030</code>. And it gets me a result, there is a handle 0x002f, and the UUID of <code class="language-plaintext highlighter-rouge">00002901-0000-1000-8000-00805f9b34fb</code> means it’s a “Characteristic User Description”. Let’s read it with <code class="language-plaintext highlighter-rouge">char-read-hnd 0x002f</code>, which gives us:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Characteristic value/descriptor: 52 47 42 57 20 34 20 62 79 74 65 73
</code></pre></div></div>
<p>And that hex value, when dropped into a hex to ASCII converter, gives us “RGBW 4 bytes”. Yeah that’s a lot of work, I think I’ll stick with the phone app for exploration. Moving on to the fun bit!</p>
<p>I know I should send a write command to the <code class="language-plaintext highlighter-rouge">0x002e</code> handle, and if I want to send a color, I need to have the hex value, surrounded by unknown, seemingly hard-coded values. So sending two different colors would be:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>char-write-cmd 0x002e 5664ff3200f0aa
char-write-cmd 0x002e 5633198000f0aa
</code></pre></div></div>
<p>Hit enter on one of them, and…IT WORKS!!!!!!</p>
<p>After I danced around a bit, I tested it a bit more. Looks like the command to send arbitrary color, where XXXXXX is hex color, is: <code class="language-plaintext highlighter-rouge">char-write-cmd 0x002e 56XXXXXX00f0aa</code>. The extra bytes before and after the hex color don’t seem to matter much, though without them it doesn’t work. Something to signify to the lightbulb I’m sending a hex value, I guess.</p>
<h3 id="other-commands">Other Commands</h3>
<p>Using the same process described above, I also looked into the ability to turn the lightbulb on and off, and the default “Warm White” and “Cool White” settings. They all <em>also</em> send to the <code class="language-plaintext highlighter-rouge">0x002e</code> handle, just sending different values. My discoveries:</p>
<ul>
<li>Turn off Light: <code class="language-plaintext highlighter-rouge">char-write-cmd 0x002e cc2433</code></li>
<li>Turn on Light: <code class="language-plaintext highlighter-rouge">char-write-cmd 0x002e cc2333</code></li>
<li>Set to “Warm white”: <code class="language-plaintext highlighter-rouge">char-write-cmd 0x002e 56000000ff0faa</code></li>
<li>Set to “Cool White”: <code class="language-plaintext highlighter-rouge">char-write-cmd 0x002e 56ffffff00f0aa</code></li>
</ul>
<p>For the warm white, I can see it sets the hex color to all zeros, but sets the two zeros after the hex color to <code class="language-plaintext highlighter-rouge">ff</code>. This implies to me there’s actually two sets of lights in there. One does the color, and one does the “Warm white” light. Sadly I only have one lightbulb, otherwise I’d be tempted to do a teardown to see if I’m right…</p>
<h2 id="conclusion">Conclusion</h2>
<p>I had my first foray into bluetooth Low Energy, and got to do some real reverse engineering! I haven’t figured out the timers yet, since it’s sending more complicated data, and I need to do more mucking about to decode what it’s sending. But this is a good place to end this post (It’s getting long!), so if I do figure it out, it’ll be a seperate post. Doing this was equal parts fun and frustrating, and I definitely feel like I understand bluetooth LE way more than I did before.</p>
<h2 id="resources">Resources</h2>
<p>Adafruit has an intro to bluetooth page if you want a good overview: <a href="https://learn.adafruit.com/introduction-to-bluetooth-low-energy">https://learn.adafruit.com/introduction-to-bluetooth-low-energy</a></p>
<p>Bluetooth’s developer guide: <a href="https://www.bluetooth.com/blog/a-developers-guide-to-bluetooth/">https://www.bluetooth.com/blog/a-developers-guide-to-bluetooth/</a></p>
<p>General bluetooth low energy info:<a href="https://www.bluetooth.com/bluetooth-resources/bluetooth-le-developer-starter-kit/">https://www.bluetooth.com/bluetooth-resources/bluetooth-le-developer-starter-kit/</a></p>
<p>Bluetooth Low Energy in 10 minutes video: <a href="https://www.youtube.com/watch?v=JSQhRyTKnW4">https://www.youtube.com/watch?v=JSQhRyTKnW4</a></p>
<p>Nordic semiconductors “devzone” site has some well written info about low energy too: <a href="https://devzone.nordicsemi.com/nordic/short-range-guides/b/bluetooth-low-energy/posts/ble-characteristics-a-beginners-tutorial">https://devzone.nordicsemi.com/nordic/short-range-guides/b/bluetooth-low-energy/posts/ble-characteristics-a-beginners-tutorial</a></p>
<p>Getting Started with Bluetooth Low Energy from Oreilly has chapter 4 online, which is about GATT: <a href="https://www.oreilly.com/library/view/getting-started-with/9781491900550/ch04.html">https://www.oreilly.com/library/view/getting-started-with/9781491900550/ch04.html</a></p>
<p>Good writeup on using <code class="language-plaintext highlighter-rouge">gatttool</code> and <code class="language-plaintext highlighter-rouge">hcitool</code> to connect to bluetooth LE devices: <a href="https://www.jaredwolff.com/get-started-with-bluetooth-low-energy/#connect-to-your-bluetooth-low-energy-device">https://www.jaredwolff.com/get-started-with-bluetooth-low-energy/#connect-to-your-bluetooth-low-energy-device</a></p>
<p>Bluetooth has a list of 16-bit UUID Numbers and what they map to. It used to be all on searchable webpages, but they’ve moved it to a PDF: <a href="https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf">https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf</a></p>“Smart” things are the wave of the future! Everyone wants some bit of tech that already exists, like a lightbulb, but now controlled through an app! Or at least, that’s what marketers have decided on. But sometimes the companies maintaining the app goes under, or decides to not support what you bought anymore, and your fancy smart lightbulb becomes, well, a $35 lightbulb. I recently got my hands on an old bluetooth lightbulb that was first made in 2015. But the phone app to control it is clunky and ugly, and hasn’t been updated since 2018. So if I want to still use it now, the options are to have an unmaintaned, potential security-risk app on my phone, or not use it. Or, be me, since I’ve been itching to learn more about bluetooth low energy. In which case, it becomes time to do some reverse engineering!Using Interrupts on the Adafruit Feather Huzzah with ESP82662021-09-08T00:00:00+00:002021-09-08T00:00:00+00:00/blog/2021/9/8/interrupts-with-adafruit-feather-huzzah-esp8266<p>It doesn’t take long learning embedded systems before you come across interrupts. Learning how to make your embedded system quickly react to changes in the real world (button presses, motion sensing, whatever) is often a default requirement for any fun projects. Since I’ve been programming on the Adafruit Feather Huzzah with ESP8266 (a mouthful, I have to say), I decided to use that for some hands-on learning.</p>
<p><img src="/assets/interrupts-with-esp8266-feather/feather_interrupt.jpg" alt="Adafruit Feather Huzzah on a breadboard with a switch, LED, a resistor, and some wires" />
<!--more--></p>
<h2 id="the-plan">The Plan</h2>
<p>Do some basic interrupts and learn more about how to use them with the ESP8266. A basic interrupt example that I’ve seen around a lot is turning on an LED for a certain amount of time when a button is pressed. So let’s do that!</p>
<blockquote>
<p><strong>NOTE</strong> I’m assuming in this post you already have the setup to run the Arduino IDE and write programs for the ESP8266.</p>
</blockquote>
<h2 id="hardware">Hardware</h2>
<p>Hardware needed:</p>
<ul>
<li><a href="https://www.adafruit.com/product/3213">Adafruit Feather Huzzah w/ ESP8266, with soldered on headers</a></li>
<li>Breadboard</li>
<li>Jumper wires</li>
<li>LED</li>
<li>300 Ohm Resistor</li>
</ul>
<p>To wire up the circuit I’ll be using, attach the LED and resistor in series, and connect to pin 14 and ground on the feather. Then attach the momentary switch to pin 4 and ground. Below is a simple drawing showing the circuit. The wire color in the diagram is just for visual clarity.</p>
<p><img src="/assets/interrupts-with-esp8266-feather/schematic.png" alt="Schematic drawing" /></p>
<h2 id="without-interrupts">Without Interrupts</h2>
<p>First, lets get the basic functionality working without interrupts. Note that I set the momentary switch as a pull up. This means when the switch is not pressed, I’ll read the pin as <code class="language-plaintext highlighter-rouge">HIGH</code>, and when it’s pressed, it’ll go to <code class="language-plaintext highlighter-rouge">LOW</code>. If I didn’t set it, the pin would not be guaranteed either <code class="language-plaintext highlighter-rouge">HIGH</code> or <code class="language-plaintext highlighter-rouge">LOW</code>, and reading the state of pin 4 wouldn’t tell me if the button was pushed or not!</p>
<p>I also used the <code class="language-plaintext highlighter-rouge">millis()</code> function instead of <code class="language-plaintext highlighter-rouge">delay()</code>. This is because <code class="language-plaintext highlighter-rouge">delay</code> doesn’t let me do anything else while I’m waiting for the LED to finish being on. If I want to use this code to do other things while the LED is on, I have to instead track the time since it was turned on, so I can do other things in the <code class="language-plaintext highlighter-rouge">loop()</code> too.</p>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="cp">#define GPIO_INTERRUPT_PIN 4
#define LED_PIN 14
#define WAIT_TIME 500
</span>
<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">lastTrigger</span> <span class="o">=</span> <span class="n">millis</span><span class="p">();</span>
<span class="kt">bool</span> <span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">//Start serial</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">115200</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Starting sketch"</span><span class="p">);</span>
<span class="c1">//Set the LED pin to output</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">LED_PIN</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="c1">//set the eventual interrupt pin as an input that is pulled up</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">GPIO_INTERRUPT_PIN</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buttonPressed</span> <span class="o">&&</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">GPIO_INTERRUPT_PIN</span><span class="p">)</span> <span class="o">==</span> <span class="n">LOW</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Button pressed"</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LED_PIN</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">lastTrigger</span> <span class="o">=</span> <span class="n">millis</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buttonPressed</span> <span class="o">&&</span> <span class="n">lastTrigger</span> <span class="o">+</span> <span class="n">WAIT_TIME</span> <span class="o"><</span> <span class="n">millis</span><span class="p">()){</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LED_PIN</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
<span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//Other functionality goes here...</span>
<span class="p">}</span></code></pre></figure>
<p>Of course most code isn’t only checking a button. Let’s add a <code class="language-plaintext highlighter-rouge">delay</code> in there to simulate doing other work.</p>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="cp">#define GPIO_INTERRUPT_PIN 4
#define LED_PIN 14
#define WAIT_TIME 500
</span>
<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">lastTrigger</span> <span class="o">=</span> <span class="n">millis</span><span class="p">();</span>
<span class="kt">bool</span> <span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">//Start serial</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">115200</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Starting sketch"</span><span class="p">);</span>
<span class="c1">//Set the LED pin to output</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">LED_PIN</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="c1">//set the eventual interrupt pin as an input that is pulled up</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">GPIO_INTERRUPT_PIN</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buttonPressed</span> <span class="o">&&</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">GPIO_INTERRUPT_PIN</span><span class="p">)</span> <span class="o">==</span> <span class="n">LOW</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Button pressed"</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LED_PIN</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">lastTrigger</span> <span class="o">=</span> <span class="n">millis</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buttonPressed</span> <span class="o">&&</span> <span class="n">lastTrigger</span> <span class="o">+</span> <span class="n">WAIT_TIME</span> <span class="o"><</span> <span class="n">millis</span><span class="p">()){</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LED_PIN</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
<span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//Other functionality goes here...</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>If you upload this code to the feather, you can see the button press is erratic. First, if you mess with the <code class="language-plaintext highlighter-rouge">delay</code> time, you can see that once the number of milliseconds you delay is longer than <code class="language-plaintext highlighter-rouge">WAIT_TIME</code>, the LED will stay on longer. This is because turning off the LED is in the <code class="language-plaintext highlighter-rouge">loop()</code> function with everything else, so while it’s in the <code class="language-plaintext highlighter-rouge">delay</code>, the code can’t turn the LED off!</p>
<p>Second, it doesn’t always register that the button was pressed. When it’s in the <code class="language-plaintext highlighter-rouge">delay</code> function (aka doing other stuff), it’s not checking if the button has switched to <code class="language-plaintext highlighter-rouge">LOW</code> (aka been pressed). Completely missing a button press is not acceptable for pretty much <em>any</em> project! Let’s fix that.</p>
<h2 id="basics-of-interrupts">Basics of Interrupts</h2>
<p>Interrupts are a way to <em>interrupt</em> the standard flow of your program. In my particular case, I want to interrupt whatever I’m doing in my <code class="language-plaintext highlighter-rouge">loop()</code> function and turn on the LED when I press the button.</p>
<p>The steps of a generic interrupt happening are:</p>
<ol>
<li>The ESP8266 is running code (both overhead and code in my <code class="language-plaintext highlighter-rouge">loop</code> function)</li>
<li>Something happens that I told the ESP8266 in my <code class="language-plaintext highlighter-rouge">setup</code> function needs to trigger an interrupt</li>
<li>The ESP8266 stops whatever is currently happening and saves the context so it can get back to it later</li>
<li>The ESP8266 looks up what it’s supposed to do when the trigger happens (aka looks for my interrupt handler code)</li>
<li>It runs my handler code</li>
<li>Once that’s done, it pulls the saved context back into its proper place, and starts up whatever it was doing before the interrupt happened.</li>
</ol>
<p>I also made a timing diagram of the button press interrupt happening, to give a more visual represenation.</p>
<p><img src="/assets/interrupts-with-esp8266-feather/timing_diagram.png" alt="Timing diagram of what was just described" /></p>
<p>So, to make this interrupt I want a reality, I have some basic setup to do:</p>
<ol>
<li>Define what I want to happen when the interrupt triggers (i.e. turn on the LED and set some variables to control how long the LED is on). This will be my interrupt handler function, also known as an interrupt service routine or ISR.</li>
<li>Set how I want to trigger the interrupt. In my case, I want to trigger on a GPIO pin.</li>
<li>Since I’m triggering off of a GPIO pin, I need to set what state I want to trigger on. Some example options would be rising (when it goes from <code class="language-plaintext highlighter-rouge">LOW</code> to <code class="language-plaintext highlighter-rouge">HIGH</code>), falling (when it goes from <code class="language-plaintext highlighter-rouge">HIGH</code> to <code class="language-plaintext highlighter-rouge">LOW</code>), or whenever there’s a change.</li>
</ol>
<h2 id="arduino-specifics">Arduino Specifics</h2>
<p>Arduino has a builtin function <code class="language-plaintext highlighter-rouge">attachInterrupt</code> that lets me set what pin and when to trigger the interrupt. They have a write up here: <a href="https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/">https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/</a>. It’s pretty straightforward. Call <code class="language-plaintext highlighter-rouge">attachInterrupt</code> with the pin to watch, the function to call when it triggers, and when to trigger it.</p>
<p>Arduino has default constants you can use for when to trigger the interrupts. They are:</p>
<blockquote>
<p>LOW to trigger the interrupt whenever the pin is low,</p>
<p>CHANGE to trigger the interrupt whenever the pin changes value</p>
<p>RISING to trigger when the pin goes from low to high,</p>
<p>FALLING for when the pin goes from high to low.</p>
</blockquote>
<p>Since I want to trigger off my button attached to pin 4, and I want to trigger it when the pin goes from <code class="language-plaintext highlighter-rouge">LOW</code> to <code class="language-plaintext highlighter-rouge">HIGH</code> (aka when a person lifts their finger off the button), I can setup the interrupt with the below code:</p>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="n">attachInterrupt</span><span class="p">(</span><span class="n">digitalPinToInterrupt</span><span class="p">(</span><span class="n">GPIO_INTERRUPT_PIN</span><span class="p">),</span> <span class="n">detectsButton</span><span class="p">,</span> <span class="n">RISING</span><span class="p">);</span></code></pre></figure>
<p>That <code class="language-plaintext highlighter-rouge">detectsButton</code> argument is the name of the interrupt handler function. Which has to be defined a little different from what the arduino documentation says because I’m using the ESP8266.</p>
<h2 id="esp8266-specifics">ESP8266 Specifics</h2>
<p>The ESP8266 has a slightly different setup than the standard chips used in Arduinos, which results in an extra step. When declaring the interrupt function, you have to prepend <code class="language-plaintext highlighter-rouge">ICACHE_RAM_ATTR</code> to the function definition. This tells the linker to put this function in RAM instead of flash, where the rest of the program goes. The exact reasons why seem a bit murky. Different posts and forum questions online give no reason beyond “you gotta put this here”, or give different reasons why. But the basics as I understand it is that the interrupt handler (aka the code that runs during the interrupt) needs to be stored in RAM on the ESP8266, not flash, where it would normally be stored without that <code class="language-plaintext highlighter-rouge">ICACHE_RAM_ATTR</code>. This is because the interrupt code can run at any time, and if the chip is in the middle of writing or reading to flash, trying to also run the interrupt handler code in flash at the same time will cause the chip to crash. Crashing is bad, so the ESP8266 Arduino code has a built-in check to make sure all interrupt handlers are in the RAM. If it’s not, the code will pre-emptively crash with an error that says “ISR not in IRAM!”.</p>
<p>So the <code class="language-plaintext highlighter-rouge">detectsButton</code> function is defined as follows:</p>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="n">ICACHE_RAM_ATTR</span> <span class="kt">void</span> <span class="nf">detectsButton</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">//NOTE because in ISR, millis() call will return the same value every time</span>
<span class="c1">//only trigger if I didn't just trigger DEBOUNCE_TIME ago</span>
<span class="c1">//lastTrigger > millis() means millis has overflowed</span>
<span class="k">if</span> <span class="p">(</span><span class="n">lastTrigger</span> <span class="o">></span> <span class="n">millis</span><span class="p">()</span> <span class="o">||</span> <span class="n">lastTrigger</span><span class="o">+</span><span class="n">DEBOUNCE_TIME</span> <span class="o"><</span> <span class="n">millis</span><span class="p">())</span>
<span class="p">{</span>
<span class="n">lastTrigger</span> <span class="o">=</span> <span class="n">millis</span><span class="p">();</span>
<span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span><span class="p">{</span>
<span class="n">bounce</span><span class="o">++</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>There’s a couple things to note here. One, my comment that starts with “NOTE” that talks about the <code class="language-plaintext highlighter-rouge">millis</code> function. The <code class="language-plaintext highlighter-rouge">millis()</code> function returns the number of milliseconds it’s been since the chip turned on. It actually uses interrupts in order to update! That interrupt is setup by the Arduino code, which is why I don’t have to setup that interrupt in my code. However, Arduino disables interrupts when you’re running an interrupt handler. Presumably so you don’t get interrupts triggering while you’re handling an interrupt and just get lost in nested interrupts forever. But this means the interrupt to update the return value for <code class="language-plaintext highlighter-rouge">millis()</code> wont run, and so it’ll return the same value the entire time you’re in an interrupt handler.</p>
<p>Second, there’s a check <code class="language-plaintext highlighter-rouge">lastTrigger+DEBOUNCE_TIME < millis()</code> that happens before it actually updates that the button was pressed. The ESP8266 says that the button has changed from <code class="language-plaintext highlighter-rouge">LOW</code> to <code class="language-plaintext highlighter-rouge">HIGH</code>, which is why it’s running this code, so why am I adding extra checks? It’s because of debouncing. The analog world can be messy (citation needed), so when the button is first pressed, or first released, the reading on pin 4 can bounce between <code class="language-plaintext highlighter-rouge">LOW</code> and <code class="language-plaintext highlighter-rouge">HIGH</code> a bit before it settles down on one or the other. During that time, the interrupt can get triggered several times. But I only want it to actually trigger once! So I add a check in there. If the last time the button was triggered was <em>really</em> recent (aka within <code class="language-plaintext highlighter-rouge">DEBOUNCE_TIME</code> milliseconds), then I assume this trigger was the button bouncing a bit, and ignore it. Because I was curious, though, I don’t completely ignore it. Instead I set the <code class="language-plaintext highlighter-rouge">bounce++</code> to add to my total bounce amount. In my <code class="language-plaintext highlighter-rouge">loop</code> code I check that variable and output to serial that I bounced, just so I could see how often it happens.</p>
<p>Lastly, there’s a check for <code class="language-plaintext highlighter-rouge">lastTrigger > millis()</code> which at first glance doesn’t make sense. The<code class="language-plaintext highlighter-rouge">lastTrigger</code> variable is set to <code class="language-plaintext highlighter-rouge">millis()</code> from the last time it was triggered, and the number of milliseconds since the chip was turned on will only go up (we’re not time-traveling!). So how can this check ever return true? The answer is overflow! The number of milliseconds since turn on is stored in an unsigned long variable. Since it’s unsigned, the variable is always positive, and since it’s a long, its size is 32 bits. This means the max number of milliseconds it can store is 2<sup>32</sup> - 1, aka 4294967295 milliseconds. Convert that to days, and you get 49.7103009259 days, aka around 50 days (which the Arduino documentation on <code class="language-plaintext highlighter-rouge">millis()</code> says). Once it gets to that number, and you add one more millisecond, the number is 33 bits long! So the code just gets rid of the topmost number, and suddenly you’re getting 0 milliseconds from <code class="language-plaintext highlighter-rouge">millis()</code>. Now, I’m unlikely to run this test code for 50 days, so I don’t <em>really</em> need it, but I like to be complete when I can.</p>
<h2 id="final-code">Final Code</h2>
<p>Now that I have all that preamble out of the way, I can put together final example code using interrupts on the ESP8266.</p>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="cp">#define GPIO_INTERRUPT_PIN 4
#define LED_PIN 14
#define WAIT_TIME 250
#define DEBOUNCE_TIME 10
</span>
<span class="k">volatile</span> <span class="kt">bool</span> <span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="k">volatile</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">lastTrigger</span> <span class="o">=</span> <span class="n">millis</span><span class="p">();</span>
<span class="k">volatile</span> <span class="kt">int</span> <span class="n">bounce</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">prevBounceCount</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">ICACHE_RAM_ATTR</span> <span class="kt">void</span> <span class="nf">detectsButton</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">//NOTE because in ISR, millis() call will return the same value every time</span>
<span class="c1">//only trigger if I didn't just trigger DEBOUNCE_TIME ago</span>
<span class="c1">//lastTrigger > millis() means millis has overflowed</span>
<span class="k">if</span> <span class="p">(</span><span class="n">lastTrigger</span> <span class="o">></span> <span class="n">millis</span><span class="p">()</span> <span class="o">||</span> <span class="n">lastTrigger</span><span class="o">+</span><span class="n">DEBOUNCE_TIME</span> <span class="o"><</span> <span class="n">millis</span><span class="p">())</span>
<span class="p">{</span>
<span class="n">lastTrigger</span> <span class="o">=</span> <span class="n">millis</span><span class="p">();</span>
<span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span><span class="p">{</span>
<span class="n">bounce</span><span class="o">++</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">115200</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Starting sketch"</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">LED_PIN</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">GPIO_INTERRUPT_PIN</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
<span class="n">attachInterrupt</span><span class="p">(</span><span class="n">digitalPinToInterrupt</span><span class="p">(</span><span class="n">GPIO_INTERRUPT_PIN</span><span class="p">),</span> <span class="n">detectsButton</span><span class="p">,</span> <span class="n">RISING</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">//lastTrigger > millis() means millis has overflowed</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buttonPressed</span> <span class="o">&&</span> <span class="p">(</span><span class="n">lastTrigger</span> <span class="o">></span> <span class="n">millis</span><span class="p">()</span> <span class="o">||</span> <span class="n">lastTrigger</span><span class="o">+</span><span class="n">WAIT_TIME</span> <span class="o"><=</span> <span class="n">millis</span><span class="p">())){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"button was pressed, time to turn off LED"</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LED_PIN</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
<span class="n">buttonPressed</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">buttonPressed</span><span class="p">){</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">LED_PIN</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">bounce</span> <span class="o">!=</span> <span class="n">prevBounceCount</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Debounced"</span><span class="p">);</span>
<span class="n">prevBounceCount</span> <span class="o">=</span> <span class="n">bounce</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//Other functionality goes here...</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">250</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>
<p>Notice how several variables are declared to be <code class="language-plaintext highlighter-rouge">volatile</code>. This is important! Setting variables to <code class="language-plaintext highlighter-rouge">volatile</code> is me telling the compiler that the variables may change at any time outside the standard code flow. I set them to <code class="language-plaintext highlighter-rouge">volatile</code> in the code so the compiler knows not to optimize them out, or to used a cached value. In this case, I’m setting several variables to <code class="language-plaintext highlighter-rouge">volatile</code> because I set them in the interrupt handler. Which means every time I access them in the <code class="language-plaintext highlighter-rouge">loop()</code> function, it’s possible that the interrupt had happened just before it, and changed those variables! This is important info for the compiler to know, and makes it so the compiled version of my code is actually what I want it to be. Embedded FM has a short article about volatile if you want to learn more: <a href="https://embedded.fm/blog/2017/2/23/explaining-the-c-keyword-volatile">https://embedded.fm/blog/2017/2/23/explaining-the-c-keyword-volatile</a></p>
<p>Now when a button is pressed (and released), the LED turns on immediately! Take some time to repeatedly press the button to turn on the LED and marvel at your new-found knowledge.
Note, however, that this works <em>completely</em> as intended only as long as the other functionality in the loop() doesn’t take longer than <code class="language-plaintext highlighter-rouge">WAIT_TIME</code> to complete. If the other functionality takes longer, than the <code class="language-plaintext highlighter-rouge">if</code> statement checking how long it’s been since last trigger won’t run in time, and the LED will stay on longer than <code class="language-plaintext highlighter-rouge">WAIT_TIME</code>. This is because turning the LED off is in the <code class="language-plaintext highlighter-rouge">loop</code> function, and so still restricted by all the other work done there. If you want an exact timing for how long the LED is on, then you’d have to add an interrupt that triggers on time, and that is outside the scope of this post. The ESP8266 does have timer interrupts, but that requires an extra library and more testing/playing around, so I’ll leave that as a potential future post.</p>
<p>In the meantime, enjoy your new knowledge, and go forth and interrupt things!</p>
<h2 id="references">References</h2>
<ul>
<li>Arduino’s way of adding interrupts: <a href="https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/">https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/</a></li>
<li>In-depth article about Arduino interrupts (focused on AVR but applicable to ESP8266): <a href="http://gammon.com.au/interrupts">http://gammon.com.au/interrupts</a></li>
<li>ESP8266 and Arduino specific interrupts: <a href="https://randomnerdtutorials.com/interrupts-timers-esp8266-arduino-ide-nodemcu/">https://randomnerdtutorials.com/interrupts-timers-esp8266-arduino-ide-nodemcu/</a></li>
<li>Arduino Documentation for <code class="language-plaintext highlighter-rouge">millis()</code>: <a href="https://www.arduino.cc/reference/en/language/functions/time/millis/">https://www.arduino.cc/reference/en/language/functions/time/millis/</a></li>
<li>ESP8266 Arduino interrupt documentation: <a href="https://arduino-esp8266.readthedocs.io/en/latest/reference.html#interrupts">https://arduino-esp8266.readthedocs.io/en/latest/reference.html#interrupts</a></li>
<li>The book Making Embedded Systems by Elicia White has a section talking about interrupts that I referenced while writing this post: <a href="https://www.oreilly.com/library/view/making-embedded-systems/9781449308889/">https://www.oreilly.com/library/view/making-embedded-systems/9781449308889/</a></li>
</ul>It doesn’t take long learning embedded systems before you come across interrupts. Learning how to make your embedded system quickly react to changes in the real world (button presses, motion sensing, whatever) is often a default requirement for any fun projects. Since I’ve been programming on the Adafruit Feather Huzzah with ESP8266 (a mouthful, I have to say), I decided to use that for some hands-on learning.How to use Quadrature Rotary Encoders2021-08-30T00:00:00+00:002021-08-30T00:00:00+00:00/blog/2021/8/30/how-to-use-quadrature-rotary-encoders<p>As part of a project I’m working on, I wanted to have a nice rotating switch that let me flip between different options. Googling around, I discovered that apparently meant I needed a rotary encoder. I bought one from adafruit, only to realize I had no idea how to use it. And oddly enough, Adafruit didn’t have a pre-existing codebase I could pull from. It was time to read some datasheets, do some experiments, and figure out how to use it.</p>
<p><img src="https://cdn-shop.adafruit.com/970x728/377-02.jpg" alt="Rotary encoder with a black rubber knob on it, in front of a grey background" /></p>
<!--more-->
<h2 id="the-hardware">The Hardware</h2>
<p>I bought the <a href="https://www.adafruit.com/product/377">rotary encoder + extras</a> from adafruit. I had originally thought to grab one from digikey or elsewhere (if only to get used to buying from other places), but the sheer amount of variables I had to know about frazzled me. How many detents are enough? What are pulses per revolution? Adafruit just gives you one option. It’s a rotary encoder, what more do you need to know! Adafruit provides a one and done, and sometimes, that’s what you want to do. Once I got it, I put the knob on it and gave it a twirl. A very satisfying clicky twisting motion, exactly what I wanted! Now to do some reading.</p>
<p>Adafruit provides the <a href="https://cdn-shop.adafruit.com/datasheets/pec11.pdf">datasheet</a>, so I can see what’s what.</p>
<p>The 3 connector prongs on one side are the A, B and common (aka ground) channels. If I connect up to them and monitor A and B as I turn the knob, I should see the pattern specified in the Quadrature table.</p>
<p><img src="/assets/using-rotary-encoder/encoder-pins-from-datasheet.png" alt="Schematic drawing of the side of the rotary encoder, showing 3 prongs labeled A, B, and C. Next to the drawing it says A stands for Channel A, B for Channel B, and C for common" /></p>
<p><img src="/assets/using-rotary-encoder/encoder-signal-from-datasheet.png" alt="Schematic drawing showing the signal from channel A and B when turned clockwise or counterclockwise" /></p>
<p>Since I started only kind of understanding this information (and frankly was just confused by that signal schematic), I decided to do some testing. Since I wanted to use the encoder with the adafruit feather huzzah with ESP8266, I wired up the simplest circuit I could, connecting channel A on the encoder to pin 4, channel B to pin 5, and the common to ground. Diagram below:</p>
<p><img src="/assets/using-rotary-encoder/encoder-testing-circuit-diagram.png" alt="circuit diagram showing wiring just described" /></p>
<h2 id="the-first-test">The First Test</h2>
<p>The simplest test is to see what happens to things on channel A and B when I turn the knob. If you look back at the Quadrature table, you can see when both signals are HIGH, it means it’s off. And the way I wired it requires the pins to be pullups. So for this rotary encoder, when nothing is happening, they’re both set to HIGH, and when I turn the knob, they go down to low, one right after the other.</p>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="cp">#define PIN_ENCODER_A 4
#define PIN_ENCODER_B 5
</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">115200</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">PIN_ENCODER_A</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">PIN_ENCODER_B</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">valA</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_A</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">valB</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_B</span><span class="p">);</span>
<span class="c1">//since these are default HIGH (aka have a pullup resistor)</span>
<span class="c1">//either being set to LOW means something is happening on the encoder</span>
<span class="k">if</span> <span class="p">(</span><span class="n">valA</span> <span class="o">==</span> <span class="n">LOW</span> <span class="o">||</span> <span class="n">valB</span> <span class="o">==</span> <span class="n">LOW</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">valA</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">" "</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">valB</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>With this code running on my feather, I can turn the know clockwise and counter clockwise, and see what I get.</p>
<p>Turned clockwise, for each “click” of the knob, I get this:</p>
<table>
<thead>
<tr>
<th>pin A</th>
<th>pin B</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>If I want, I can just put those two values next to each other and get a binary number. So it goes from 11, to 01, to 00, to 10, to 11. With the decimal equivalent being: 3, 1, 0, 2, 3</p>
<p>So if I track the previous state and the current state, I can tell it’s going clockwise if any of these are true:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>previous state->current state
3->1
1->0
0->2
2->3
</code></pre></div></div>
<p>From this I can see I’ll have to at least track current and previous state, because it matters what state it’s coming from. Just knowing current state is “0” doesn’t mean anything about direction.</p>
<p>Let’s see if that pattern is different when it’s turned counter-clockwise. The values end up being:</p>
<table>
<thead>
<tr>
<th>pin A</th>
<th>pin B</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>Which is a different pattern! That’s good, otherwise I’d have to come up with a completely different way of figuring this out. In decimal, it would be: 3, 2, 0, 1, 3</p>
<p>So it’s going counterclockwise if:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>3->2
2->0
0->1
1->3
</code></pre></div></div>
<h2 id="second-test---lookup-tables">Second Test - Lookup tables</h2>
<p>Since I’ll have to do this in code eventually anyway, let’s do 1 to mean clockwise and -1 to mean counter clockwise. I can then list out all possible combinations of a previous and current state, and determine which way I’m going, or if I’m missing anything.</p>
<table>
<thead>
<tr>
<th>previous state</th>
<th>current state</th>
<th>direction</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>0</td>
<td>UNDEFINED</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
<td>-1</td>
</tr>
<tr>
<td>0</td>
<td>2</td>
<td>1</td>
</tr>
<tr>
<td>0</td>
<td>3</td>
<td>UNDEFINED</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>UNDEFINED</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>UNDEFINED</td>
</tr>
<tr>
<td>1</td>
<td>3</td>
<td>-1</td>
</tr>
<tr>
<td>2</td>
<td>0</td>
<td>-1</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>UNDEFINED</td>
</tr>
<tr>
<td>2</td>
<td>2</td>
<td>UNDEFINED</td>
</tr>
<tr>
<td>2</td>
<td>3</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>0</td>
<td>UNDEFINED</td>
</tr>
<tr>
<td>3</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>2</td>
<td>-1</td>
</tr>
<tr>
<td>3</td>
<td>3</td>
<td>UNDEFINED</td>
</tr>
</tbody>
</table>
<p>Based on this, I can see there’s a lot of options that don’t mean the encoder went clockwise OR counter clockwise. Looking at those undefined values, there’s two separate groups. If the previous and current values from the encoder are the same, that just means I read the values so fast, it didn’t have time to change (or in the case of 3, the encoder isn’t moving at all). So those just mean it didn’t move. For the other group of undefined values, they’re harder to categorize. Going from 0 to 3 means EITHER I moved clockwise so fast I went from 0 to 2 to 3 before my code had a chance to read the encoder values, OR I moved it <em>counter</em> clockwise so fast I went from 0 to <strong>1</strong> to 3. So that tells me the encoder rotated, but I don’t know which way! I’m not sure how to solve that, so I’m just going to treat that as a different “SKIPPED VALUE” category.</p>
<p>I can reorganize the data to make it a bit more readable (at least to me), by putting the previous value as the first column, and the current value as the first row, like this:</p>
<table>
<tbody>
<tr>
<td> </td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>0</td>
<td>DIDN’T MOVE</td>
<td>-1</td>
<td>1</td>
<td>SKIPPED A VALUE</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>DIDN’T MOVE</td>
<td>SKIPPED A VALUE</td>
<td>-1</td>
</tr>
<tr>
<td>2</td>
<td>-1</td>
<td>SKIPPED A VALUE</td>
<td>DIDN’T MOVE</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>SKIPPED A VALUE</td>
<td>1</td>
<td>-1</td>
<td>DIDN’T MOVE</td>
</tr>
</tbody>
</table>
<p>Well hey, that looks an awful lot like a lookup table, a 4x4 array with the indices corresponding to the values. Let’s do that! For the “DIDN’T MOVE” category, I can just set it to 0, and for when I skip values, I’ll do 2, a clearly wrong value. With that, I get the below table:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{0, -1, 1, 2}
{1, 0, 2, -1}
{-1, 2, 0, 1}
{2, 1, -1, 0}
</code></pre></div></div>
<p>With this planning, I can now try some code out and see if it works.</p>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="cp">#define PIN_ENCODER_A 4
#define PIN_ENCODER_B 5
</span>
<span class="kt">int</span> <span class="n">prevVal</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">newVal</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">lookupTable</span><span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span>
<span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">},</span>
<span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span>
<span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">}</span> <span class="p">};</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">115200</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">PIN_ENCODER_A</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">PIN_ENCODER_B</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">valA</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_A</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">valB</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_B</span><span class="p">);</span>
<span class="n">prevVal</span> <span class="o">=</span> <span class="p">(</span><span class="n">valA</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">valB</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">valA</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_A</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">valB</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_B</span><span class="p">);</span>
<span class="n">newVal</span> <span class="o">=</span> <span class="p">(</span><span class="n">valA</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">valB</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">info</span> <span class="o">=</span> <span class="n">lookupTable</span><span class="p">[</span><span class="n">prevVal</span><span class="p">][</span><span class="n">newVal</span><span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="n">info</span> <span class="o">==</span> <span class="mi">1</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"clockwise "</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">prevVal</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"->"</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">newVal</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">info</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"counter clockwise "</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">prevVal</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"->"</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">newVal</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">info</span> <span class="o">==</span> <span class="mi">2</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"skipped a value"</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">prevVal</span> <span class="o">=</span> <span class="n">newVal</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<h2 id="final-code---tracking-state">Final Code - Tracking State</h2>
<p>This correctly understands clockwise and counterclockwise movement. HOWEVER, there’s two issues. One, it’s triggering roughly 4 times each detent, and Two sometimes the code manages to get a bounce or something else wonky, and it reads, say, 3 clockwise and one counterclockwise movement while I’m moving it clockwise. So I want to track all the states it passes through, and then figure out which way its going, ignoring those occasional misreads.</p>
<blockquote>
<p><strong>NOTE</strong> “detent” is a fancy word for that “click” feeling you get with rotary encoders. Each “click” position is a detent.</p>
</blockquote>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="cp">#define PIN_ENCODER_A 4
#define PIN_ENCODER_B 5
</span>
<span class="kt">int</span> <span class="n">prevVal</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">newVal</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">clockState</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">counterClockState</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="c1">//lookup table, first index is previous value</span>
<span class="c1">//second index is current value</span>
<span class="c1">//says if it's part of the sequence when moving</span>
<span class="c1">//clockwise (1) or counterclockwise (-1)</span>
<span class="c1">//didn't move (0) or skipped a value (2)</span>
<span class="kt">int</span> <span class="n">lookupTable</span><span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span>
<span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">},</span>
<span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span>
<span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">}</span> <span class="p">};</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">115200</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">PIN_ENCODER_A</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">PIN_ENCODER_B</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">valA</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_A</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">valB</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_B</span><span class="p">);</span>
<span class="n">prevVal</span> <span class="o">=</span> <span class="p">(</span><span class="n">valA</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">valB</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">valA</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_A</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">valB</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">PIN_ENCODER_B</span><span class="p">);</span>
<span class="n">newVal</span> <span class="o">=</span> <span class="p">(</span><span class="n">valA</span> <span class="o"><<</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">valB</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">info</span> <span class="o">=</span> <span class="n">lookupTable</span><span class="p">[</span><span class="n">prevVal</span><span class="p">][</span><span class="n">newVal</span><span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="n">info</span> <span class="o">==</span> <span class="mi">1</span><span class="p">){</span>
<span class="n">clockState</span> <span class="o">|=</span> <span class="p">(</span><span class="mi">1</span> <span class="o"><<</span> <span class="n">newVal</span><span class="p">);</span> <span class="c1">//set the bit to 1</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">info</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">){</span>
<span class="n">counterClockState</span> <span class="o">|=</span> <span class="p">(</span><span class="mi">1</span> <span class="o"><<</span> <span class="n">newVal</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">info</span> <span class="o">==</span> <span class="mi">2</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"skipped a value"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">prevVal</span> <span class="o">!=</span> <span class="n">newVal</span> <span class="o">&&</span> <span class="n">newVal</span> <span class="o">==</span> <span class="mi">3</span><span class="p">){</span>
<span class="c1">//changed to the non moving state, lets figure out what direction we went!</span>
<span class="c1">//for each clockwise and counterclockwise, the encoder state goes through 4 distinct states</span>
<span class="c1">//make sure it's gone through at least 3 of those (and assume if one is missing it's because I didn't read fast enough)</span>
<span class="k">if</span> <span class="p">(</span><span class="n">clockState</span> <span class="o">==</span> <span class="mb">0b1011</span> <span class="o">||</span> <span class="n">clockState</span> <span class="o">==</span> <span class="mb">0b1101</span> <span class="o">||</span> <span class="n">clockState</span> <span class="o">==</span> <span class="mb">0b1110</span> <span class="o">||</span> <span class="n">clockState</span> <span class="o">==</span> <span class="mb">0b1111</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Result was clockwise"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">counterClockState</span> <span class="o">==</span> <span class="mb">0b1011</span> <span class="o">||</span> <span class="n">counterClockState</span> <span class="o">==</span> <span class="mb">0b1101</span> <span class="o">||</span> <span class="n">counterClockState</span> <span class="o">==</span> <span class="mb">0b1110</span> <span class="o">||</span> <span class="n">counterClockState</span> <span class="o">==</span> <span class="mb">0b1111</span><span class="p">){</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Result was COUNTER clockwise"</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">clockState</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">counterClockState</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">prevVal</span> <span class="o">=</span> <span class="n">newVal</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>This seems to work! I get a single “result was blah” for every turn, and it seems to be the correct rotation, too! The remaining issue depends on the other code I use this with. This code assumes I’ll be able to read at least 3 out of the 4 states the rotary encoder goes through every time it turns left or right. If I’m checking the encoder in a main loop, and my other code goes really slow, I may only get one or two states. An alternative to this would be setting up an interrupt, so it jumps to reading the encoder every time it changes state. However, interrupts are outside the scope of this blog post, so I’ll leave that as an exercise for the reader.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Hopefully this gives more info on what to expect when using a rotary encoder in your future projects. It’s a lot more complicated than a potentiometer, but that lovely clicky feeling can be perfect for switching between a bunch of options. And now you have the knowledge to use them. So go forth and get clicky!</p>
<h2 id="resources">Resources</h2>
<ul>
<li>Datasheet for the rotary encoder <a href="https://cdn-shop.adafruit.com/datasheets/pec11.pdf">https://cdn-shop.adafruit.com/datasheets/pec11.pdf</a></li>
<li>Sparkfun document talking about reading rotary encoders<a href="https://cdn.sparkfun.com/datasheets/Robotics/How%20to%20use%20a%20quadrature%20encoder.pdf">https://cdn.sparkfun.com/datasheets/Robotics/How%20to%20use%20a%20quadrature%20encoder.pdf</a></li>
<li>Learning about the Arduino IDE serial plotter <a href="https://diyrobocars.com/2020/05/04/arduino-serial-plotter-the-missing-manual/">https://diyrobocars.com/2020/05/04/arduino-serial-plotter-the-missing-manual/</a></li>
<li>Adafruit’s example using a rotary encoder<a href="https://learn.adafruit.com/pro-trinket-rotary-encoder/example-rotary-encoder-volume-control">https://learn.adafruit.com/pro-trinket-rotary-encoder/example-rotary-encoder-volume-control</a></li>
<li>Document about rotary encoders <a href="https://web.archive.org/web/20120208215116/http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino">https://web.archive.org/web/20120208215116/http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino</a></li>
<li>Pinout for the Adafruit Huzzah with ESP8266 <a href="https://cdn-learn.adafruit.com/assets/assets/000/046/211/original/Huzzah_ESP8266_Pinout_v1.2.pdf?1504807178">https://cdn-learn.adafruit.com/assets/assets/000/046/211/original/Huzzah_ESP8266_Pinout_v1.2.pdf?1504807178</a></li>
</ul>As part of a project I’m working on, I wanted to have a nice rotating switch that let me flip between different options. Googling around, I discovered that apparently meant I needed a rotary encoder. I bought one from adafruit, only to realize I had no idea how to use it. And oddly enough, Adafruit didn’t have a pre-existing codebase I could pull from. It was time to read some datasheets, do some experiments, and figure out how to use it.Setting up ESP8266 with VSCode, Arduino, and Make2021-08-26T00:00:00+00:002021-08-26T00:00:00+00:00/blog/2021/8/26/esp8266-with-VSCode-and-arduino<p>Continuing my exploration of embedded systems, I decided to try my hand at the ESP8266, a popular microcontroller. It’s apparently being phased out and replaced with the ESP32, but it still has a lot of fuctionality, and perhaps more importantly, I already had one on a dev board laying around.</p>
<p>Because I’m all about learning, and also about doing things the hard way, I decided to use a different toolchain setup than what Adafruit suggests (which is just using the arduino ecosystem). Instead, I’ll go for something a little more complicated…</p>
<!--more-->
<h2 id="plan">Plan</h2>
<p>The plan is to use the ESP8266, in this case on the <a href="https://www.adafruit.com/product/2821">adafruit feather Huzzah with ESP8266</a>, with the Arduino libraries, but using VSCode instead of the Arduino IDE. In the spirit of KISS (Keep It Simple Stupid), I decided to use Make to glue everything together. Happily I didn’t have to do this all from scratch, and mainly had to tweak things instead. Let’s get into it.</p>
<h2 id="benefits">Benefits</h2>
<p>Why am I even doing this in the first place? Well:</p>
<ul>
<li><strong>Arduino Libraries are easy to use</strong> - I <em>could</em> work on getting espressif’s SDK for the ESP8266 going, and figure out how to flash the code onto the huzzah myself. But frankly, that’s a bit too much reinventing the wheel right now. I want to get something functional, and the code I have already uses Arduino libraries and calls, so why re-write it all? Plus, getting more libraries is really easy with the Arduino IDE.</li>
<li><strong>More Useful IDE</strong> - this is very subjective, but frankly, I like VSCode a lot better than the Arduino IDE. I got a file explorer, a terminal, and a text editor with syntax highlighting, what more could a gal need? Its level of flexibility means I can do everything I want in it (including writing this blog post). I don’t have to relearn a new IDE for embedded stuff, I can stick with what I know. Given all there is to know about embedded systems, I’m willing to skip the less interesting bits.</li>
<li><strong>Testing</strong> - I did googling but I couldn’t find anything about doing unit tests in the Arduino IDE. I want to build more complex programs, which means testing. Debugging boneheaded errors because I <em>couldn’t</em> do unit tests seemed very silly. If I’m going to debug boneheaded errors, it’s because I <em>decided</em> not to do unit tests. And again, there’s a lot for me to learn here, doing unit tests as I go will help me on my embedded systems adventure.</li>
<li><strong>Flexibility</strong> - If I want to have multiple builds, or add extra things to my build process, I can! I have to argue with make about it, but it’s at least possible, and kind of already a given with the tools I’m using.</li>
<li><strong>Local</strong> - I know there’s a couple online embedded IDE’s out there (Platformio comes to mind), but call me old-fashioned: I like to have code on my computer. Sure, I’ll back it up (normally to github), but having a local copy, and not relying on an online cloud service, feels like one less thing to worry about. If my code breaks or disappears, it’s because of me, not because a cloud service decided they wanted more money and paywalled me out of my code.</li>
</ul>
<h2 id="the-software">The Software</h2>
<h3 id="arduino-ide">Arduino IDE</h3>
<p>The arduino IDE is actually still needed for this setup. I know, I know, it seems silly to download something you don’t plan on using. But it does provide easy access to arduino libraries, plus a nice serial monitor and plotter. I don’t like coding in it, but those are nice features to have, so it’s simpler to just download it and use the bits you care about. Download the software directly from Arduino on their <a href="https://www.arduino.cc/en/software">software download page</a>. Make sure to select the correct version, and don’t get distracted by the web editor they’re advertising. You want the downloadable version.</p>
<h3 id="vscode">VSCode</h3>
<p>VSCode, aka Visual Studio Code, is made by Microsoft, and is completely different than their large and somewhat unwieldy Visual Studio IDE. Yes, Microsoft is still terrible at naming things. VSCode is actually open source, and free for private and commercial use. It also has a lot of plugins, built-in terminal, syntax highlighting, and is pretty lightweight for how useful it is. Think of it as somewhere between Sublime and Eclipse/Visual Studio IDE. It also runs on Mac, Linux, and Windows. You can download it from <a href="https://code.visualstudio.com/">Microsoft’s visual studio code website</a></p>
<h3 id="makefile">Makefile</h3>
<p>Make is old-school (sorry if you’re reading this and remember when it was new. But like, it’s true. You’re old-school now. It came out in ‘76!) It’s a build automation tool that runs on the command line. You can make custom production, dev, test, whatever-else build processes. You can probably get it to clean your kitchen. The commands can be arcane and confusing, but it can do a little bit of everything if you learn the right incantation.
If you have linux, you probably already have it.</p>
<h3 id="the-others">The others</h3>
<p>I’m also using git, python, and g++. The pre-made makefile also calls some perl scripts. Just to give you a full understanding of what I’m using.</p>
<h2 id="the-set-up">The Set-up</h2>
<p>First, make sure you have all of the above listed software. Make sure they all seem to work. Now lets start tweaking things.</p>
<h3 id="arduino-libraries">Arduino Libraries</h3>
<p>Since you want to work on an ESP8266, first you’ll have to download some libraries. The bare-minimum is the ESP8266 board library. This is from <a href="https://github.com/esp8266/Arduino">https://github.com/esp8266/Arduino</a>, and the install instructions are pretty straightforward. Add a new board manager URL, then download the ESP8266 board.</p>
<p>To make sure it works, I’d suggest trying to flash one of the example sketches to the esp8266, make it blink or run a wifi scan.</p>
<h3 id="vscode-1">VSCode</h3>
<p>I Installed a Microsoft-written plugin that helps with syntax: <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools">https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools</a>. The webpage shows the install instructions. Later there’s some VSCode config files you can add to your project to make its error alerts more useful.</p>
<h3 id="makefile-1">Makefile</h3>
<p>There’s actually two makefiles for this. The first is a pre-built one that came from <a href="https://github.com/plerup/makeEspArduino">https://github.com/plerup/makeEspArduino</a>. This has install instructions, and works! But it didn’t support how I setup my project (see below), so I forked it and modified it. It’s now available on my <a href="https://github.com/dthurow/makeEspArduino">github repo</a> with the change I had to make.</p>
<p>That’s the first makefile, the second is a custom one that will live in your project. I’ll explain more below.</p>
<h2 id="project-setup">Project setup</h2>
<p>Folder setup described below. -> means it’s a directory, tabs indicate which files are in what folder (e.g. “unity” folder is inside the “test” folder).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>->Project name
->.vscode
->build
->doc
->test
->unity
unity_internals.h
unity.c
unity.h
->src
->inc
->makeEspArduino
makefile
readme.md
.gitignore
.gitmodules
</code></pre></div></div>
<p>I’ll go through each of these folder and files to explain what’s in them.</p>
<h3 id="makeesparduino">makeEspArduino</h3>
<p>This is actually a git submodule. This folder contains the <a href="https://github.com/dthurow/makeEspArduino">https://github.com/dthurow/makeEspArduino</a> repo. It lets you keep all your code in one place. The <code class="language-plaintext highlighter-rouge">.gitmodules</code> file (explained below) automatically pulls that in when you do <code class="language-plaintext highlighter-rouge">git clone --recurse-submodules</code> on any project you make following this setup.</p>
<h3 id="gitmodules">.gitmodules</h3>
<p>This lets you have git repos in folders inside other git repos. In this case, we’re adding the <a href="https://github.com/dthurow/makeEspArduino">makeEspArduino</a> into the project. The contents of this file are:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[submodule "makeEspArduino"]
path = makeEspArduino
url = git@github.com:Dthurow/makeEspArduino.git
</code></pre></div></div>
<h3 id="makefile-2">makefile</h3>
<p>This file does two things:</p>
<ol>
<li>Sets the configuration variables that the <code class="language-plaintext highlighter-rouge">makeEspArduino</code> uses</li>
<li>Sets up the ability to run tests (I use the <a href="http://www.throwtheswitch.org/unity">unity framework</a>)</li>
</ol>
<p>To make this work for you, you’ll have to make sure that:</p>
<ul>
<li>the <code class="language-plaintext highlighter-rouge">LIBS</code> directories are where your arduino libraries are.</li>
<li>The <code class="language-plaintext highlighter-rouge">SKETCH</code> variable is set to your main file (that contains your <code class="language-plaintext highlighter-rouge">setup()</code> and <code class="language-plaintext highlighter-rouge">loop()</code> functions)</li>
<li>Have g++ downloaded</li>
<li>Set the <code class="language-plaintext highlighter-rouge">BOARD</code> to the correct value. To figure out what it should be, you can run <code class="language-plaintext highlighter-rouge">make list_boards</code> and the <code class="language-plaintext highlighter-rouge">makeESPArduino</code> file will spit out a list of accepted boards. It also has a <code class="language-plaintext highlighter-rouge">generic</code> option if yours isn’t on the list</li>
</ul>
<figure class="highlight"><pre><code class="language-make" data-lang="make"><span class="nv">DIR</span> <span class="o">:=</span> <span class="nv">${CURDIR}</span>
<span class="nv">SKETCH</span> <span class="o">=</span> <span class="nv">$(DIR)</span>/src/[YOUR MAIN FILE HERE]
<span class="nv">BUILD_DIR</span> <span class="o">=</span> <span class="nv">$(DIR)</span>/build
<span class="nv">BOARD</span> <span class="o">=</span> huzzah
<span class="nv">LIBS</span> <span class="o">=</span> <span class="nv">$(HOME)</span>/.arduino15/packages/esp8266/hardware/esp8266/2.7.4/libraries <span class="nv">$(HOME)</span>/Arduino/libraries
<span class="nv">EXCLUDE_DIRS</span> <span class="o">=</span> <span class="nb">test</span>
<span class="k">include</span><span class="sx"> $(DIR)/makeEspArduino/makeEspArduino.mk</span>
<span class="c">#everything below here is for setting up tests
</span><span class="nv">TARGET_EXTENSION</span><span class="o">=</span>.out
<span class="c">#Path Definitions
</span><span class="nv">PATHU</span> <span class="o">=</span> <span class="nb">test</span>/unity/
<span class="nv">PATHS</span> <span class="o">=</span> src/
<span class="nv">PATHT</span> <span class="o">=</span> <span class="nb">test</span>/
<span class="nv">PATHI</span> <span class="o">=</span> inc/
<span class="nv">PATHB</span> <span class="o">=</span> build/
<span class="c">#determine our source files
</span><span class="nv">SRCU</span> <span class="o">=</span> <span class="nv">$(PATHU)</span>unity.c
<span class="nv">SRCS</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">wildcard</span> <span class="nv">$(PATHS)</span><span class="k">*</span>.cpp<span class="nf">)</span>
<span class="nv">SRCT</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">wildcard</span> <span class="nv">$(PATHT)</span><span class="k">*</span>.cpp<span class="nf">)</span>
<span class="nv">SRC</span> <span class="o">=</span> <span class="nv">$(SRCU)</span> <span class="nv">$(SRCS)</span> <span class="nv">$(SRCT)</span>
<span class="c">#Files We Are To Work With
</span><span class="nv">OBJU</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">patsubst</span> <span class="nv">$(PATHU)</span>%.c,<span class="nv">$(PATHB)</span>%.o,<span class="nv">$(SRCU)</span><span class="nf">)</span>
<span class="nv">OBJS</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">patsubst</span> <span class="nv">$(PATHS)</span>%.cpp,<span class="nv">$(PATHB)</span>%.o,<span class="nv">$(SRCS)</span><span class="nf">)</span>
<span class="nv">OBJT</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">patsubst</span> <span class="nv">$(PATHT)</span>%.cpp,<span class="nv">$(PATHB)</span>%.o,<span class="nv">$(SRCT)</span><span class="nf">)</span>
<span class="nv">OBJ</span> <span class="o">=</span> <span class="nv">$(OBJU)</span> <span class="nv">$(OBJS)</span> <span class="nv">$(OBJT)</span>
<span class="c">#Other files we care about
</span><span class="nv">DEP</span> <span class="o">=</span> <span class="nv">$(PATHU)</span>unity.h <span class="nv">$(PATHU)</span>unity_internals.h
<span class="nv">TGT</span> <span class="o">=</span> <span class="nv">$(PATHB)</span><span class="nb">test</span><span class="nv">$(TARGET_EXTENSION)</span>
<span class="c">#Tool Definitions
</span><span class="nv">CC</span><span class="o">=</span>g++
<span class="nv">CFLAGS</span><span class="o">=</span><span class="nt">-I</span><span class="nb">.</span> <span class="nt">-I</span><span class="nv">$(PATHU)</span> <span class="nt">-I</span><span class="nv">$(PATHI)</span> <span class="nt">-I</span><span class="nv">$(PATHS)</span> <span class="nt">-DTEST</span>
<span class="nl">test</span><span class="o">:</span> <span class="nf">$(PATHB) $(TGT)</span>
<span class="nb">echo</span> <span class="s2">"running tests"</span>
./<span class="nv">$(TGT)</span>
<span class="nl">$(PATHB)%.o</span><span class="o">::</span> <span class="nf">$(PATHS)%.cpp $(DEP)</span>
<span class="nb">echo</span> <span class="s2">"source compiling"</span>
<span class="nv">$(CC)</span> <span class="nt">-c</span> <span class="nv">$(CFLAGS)</span> <span class="nv">$<</span> <span class="nt">-o</span> <span class="nv">$@</span>
<span class="nl">$(PATHB)%.o</span><span class="o">::</span> <span class="nf">$(PATHT)%.cpp $(DEP)</span>
<span class="nb">echo</span> <span class="s2">"tests compiling"</span>
<span class="nv">$(CC)</span> <span class="nt">-c</span> <span class="nv">$(CFLAGS)</span> <span class="nv">$<</span> <span class="nt">-o</span> <span class="nv">$@</span>
<span class="nl">$(PATHB)%.o</span><span class="o">::</span> <span class="nf">$(PATHU)%.c $(DEP)</span>
<span class="nb">echo</span> <span class="s2">"unity compiling"</span>
<span class="nv">$(CC)</span> <span class="nt">-c</span> <span class="nv">$(CFLAGS)</span> <span class="nv">$<</span> <span class="nt">-o</span> <span class="nv">$@</span>
<span class="nl">$(TGT)</span><span class="o">:</span> <span class="nf">$(OBJ)</span>
<span class="nb">echo</span> <span class="s2">"linking"</span>
<span class="nv">$(CC)</span> <span class="nt">-o</span> <span class="nv">$@</span> <span class="nv">$^</span>
<span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">test</span></code></pre></figure>
<h3 id="test">test</h3>
<p>This folder is where you’ll put your test files (e.g. <code class="language-plaintext highlighter-rouge">testMyCoolCode.cpp</code>). Your tests can use the unity framework, which you can find out more about here: <a href="http://www.throwtheswitch.org/unity">http://www.throwtheswitch.org/unity</a>. You only need the three files I list in the folder setup, and you can get the latest from github <a href="https://github.com/ThrowTheSwitch/Unity/tree/master/src">https://github.com/ThrowTheSwitch/Unity/tree/master/src</a>.</p>
<h3 id="vscode-2">.vscode</h3>
<p>This folder stores VSCode-specific config files that override your default configs on a project-specific basis. The <code class="language-plaintext highlighter-rouge">makeEspArduino</code> makefile actually has a command that auto-creates this info for you. Once the makefile and your main source file are created, you can run <code class="language-plaintext highlighter-rouge">make vscode</code> and it will autogenerate your <code class="language-plaintext highlighter-rouge">.vscode</code> folder. In my case, though, to get VSCode’s syntax checker to fully work, I had to update the <code class="language-plaintext highlighter-rouge">includePath</code> in the <code class="language-plaintext highlighter-rouge">c_cpp_properties.json</code> file. I updated mine to:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> "includePath": [
"${env:HOME}/.arduino15/packages/esp8266/hardware/esp8266/2.7.4/tools/sdk/include",
"${env:HOME}/.arduino15/packages/esp8266/hardware/esp8266/2.7.4/tools/sdk/lwip2/include",
"${env:HOME}/.arduino15/packages/esp8266/hardware/esp8266/2.7.4/tools/sdk/libc/xtensa-lx106-elf/include",
"${env:HOME}/.arduino15/packages/esp8266/hardware/esp8266/2.7.4/cores/esp8266",
"${env:HOME}/.arduino15/packages/esp8266/hardware/esp8266/2.7.4/variants/generic",
"${env:HOME}/.arduino15/packages/esp8266/hardware/esp8266/2.7.4/libraries/**",
"${env:HOME}/Arduino/libraries/**",
"${workspaceFolder}/build",
"${workspaceFolder}/src"
],
</code></pre></div></div>
<p>And then VSCode no longer errored out on not seeing the Arduino Library folders.</p>
<h3 id="gitignore">.gitignore</h3>
<p>This one’s simple, just ignore the build folder and the special vscode folder:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>build
.vscode
</code></pre></div></div>
<h3 id="src">src</h3>
<p>Where your actual production code lives! I know, there’s a lot of other <em>stuff</em> this project has, but honest, it’s all there for a good reason.</p>
<h3 id="inc">inc</h3>
<p>Honestly I’m on the fence if you really need this folder. This can be used to include needed header files. You can also just keep them in <code class="language-plaintext highlighter-rouge">src</code>, I won’t tell.</p>
<h3 id="readmemd">readme.md</h3>
<p>A good file for any project, so you can write up setup or contribution info.</p>
<h3 id="build">build</h3>
<p>This is where the makefiles will build out any intermediary files and where it’ll put the file compiled version of the code. You can clear this folder out by typing <code class="language-plaintext highlighter-rouge">make clean</code>. Sometimes the default <code class="language-plaintext highlighter-rouge">make all</code> errors because of linker issues. In that case, run a <code class="language-plaintext highlighter-rouge">make clean</code> then <code class="language-plaintext highlighter-rouge">make all</code>.</p>
<h3 id="doc">doc</h3>
<p>A place to put any documentation you may have! You do keep written documentation, right? Because “self-documenting code” isn’t actually a thing? Yeah of course you do, good job you.</p>
<h1 id="the-final-result">The Final Result</h1>
<p>Hopefully, a working project! I’ve put together the template on github <a href="https://github.com/Dthurow/generic-esp8266-project-with-vscode-and-arduino">https://github.com/Dthurow/generic-esp8266-project-with-vscode-and-arduino</a> that you can pull down if you want to do that instead of building it out manually. Please do pull requests or open issues with any updates you may have, I’m curious if this project will be useful for others, or if there’s other ways of doing things I just don’t know about.</p>
<p>Good luck and happy programming!</p>Continuing my exploration of embedded systems, I decided to try my hand at the ESP8266, a popular microcontroller. It’s apparently being phased out and replaced with the ESP32, but it still has a lot of fuctionality, and perhaps more importantly, I already had one on a dev board laying around. Because I’m all about learning, and also about doing things the hard way, I decided to use a different toolchain setup than what Adafruit suggests (which is just using the arduino ecosystem). Instead, I’ll go for something a little more complicated…Mindfulness Bracelet, Learning Batteries, and Forgetting to KISS2021-07-28T00:00:00+00:002021-07-28T00:00:00+00:00/blog/2021/7/28/adafruit-mindfulness-bracelet<p>Setting up Blinky on various microcontrollers is one thing, actually having a working embedded system is another. So, I decided I needed something relatively easy, that preferably used what I had around already, and used the conductive thread that I had recently gotten from Adafruit as a present.</p>
<p>After some thinking, I came across a simple idea: I’ve been stressed a lot recently, and my back has been storing that all in the form of painful knots. So how about I made something that let me remember to relax my back throughout the day! I didn’t want to have yet another app sending notifications, so how about something that buzzed, maybe a wearable watch? I did some googling, and came upon the <a href="https://learn.adafruit.com/buzzing-mindfulness-bracelet/overview">Adafruit mindfulness bracelet</a>. I already had the Gemma M0, and I could use conductive thread to sew the circuit onto a simple nylon bracelet. AND the code was obviously really simple, just wait a minute or two, then vibrate, then wait. It would be a simple and quick project to dip my toes into full embedded systems!</p>
<p>Or so I thought.</p>
<!--more-->
<h3 id="the-plan">The Plan</h3>
<p>Like I said, I wanted to keep it simple. I’m a big believer in the KISS principle, aka Keep It Simple, Stupid. I’m partly a big proponent of it because I so often forget it myself when I’m working on fun side projects. I decided to use the Adafruit project as a basis, but do some minor mods to make sure I actually understood what all was happening. I don’t want to mindlessly follow instructions and get an end result I don’t understand. The modifications I wanted to do were simple:</p>
<ol>
<li><strong>Change the wrist strap</strong>
I didn’t really like the design of Adafruit’s bracelet. It just wasn’t my style, you know? So I bought a cheap nylon strap from my local hardware store. I’d just sew all the components onto it, and use the buckle it came with to attach to my arm. Simple wristband with a bunch of electronics on it seemed my style.</li>
<li><strong>Use Coin cell batteries</strong>
Not only did I not have the battery they recommend, I also don’t really like the concept of lipoly batteries attached to me unless they’re in a rigid case. I don’t want them bending too much and exploding while attached. I’m just funny that way. So instead I decided to try my coin cell batteries. They’re much better in terms of size, less explode-y, and I even have sewable battery holders that would fit perfectly on the strap
<blockquote>
<p><strong>Future Danielle Note</strong> This causes problems later down the way. I’m not sure how Adafruit attaches their battery at the end, but it may be worth the work if you’re trying to duplicate my work.</p>
</blockquote>
</li>
<li><strong>Add some code</strong>
I’m looking to learn more about embedded systems <em>programming</em>, not just how to solder or build circuits. Using only the pre-made code seems a bit of a cheat. I knew I could add some extra functionality pretty easily, and that’d let me practice my CircuitPython as well. A win-win.</li>
</ol>
<h3 id="hardware-side">Hardware Side</h3>
<h4 id="gathering-the-hardware">Gathering the hardware</h4>
<p>Adafruit lists required parts, and I mostly followed that (except for the modifications I list above). The final parts list is below.</p>
<p><strong>Hardware Needed</strong></p>
<ul>
<li><a href="https://www.adafruit.com/product/3501">Gemma M0</a></li>
<li><a href="https://www.adafruit.com/product/1201">vibrating mini disc motor</a></li>
<li><a href="https://www.adafruit.com/product/755">1N4001 diode</a></li>
<li><a href="https://www.adafruit.com/product/756">PN2222 NPN transistor</a></li>
<li>~200-1K ohm resistor</li>
<li>2 <a href="https://www.adafruit.com/product/654">CR2032 coin batteries</a></li>
<li>2 <a href="https://www.adafruit.com/product/653">coin battery holders</a></li>
<li><a href="https://www.adafruit.com/product/640">conductive thread</a></li>
<li>nylon strap roughly 1 inch wide</li>
<li>buckle for nylon strap</li>
</ul>
<p><strong>Tools Needed</strong></p>
<ul>
<li>soldering iron and accessories</li>
<li>scissors</li>
<li>ruler</li>
<li>pen or marker</li>
<li>lighter for melting ends of the nylon strap</li>
<li>multimeter</li>
</ul>
<h4 id="planning-the-circuit">Planning the Circuit</h4>
<p>The adafruit project has images and text describing what circuit you need to make, but no actual circuit schematic. Walking through what was needed, I arrived at the below circuit:</p>
<p><img src="/assets/adafruit-mindfulness-bracelet/circuit_schematic.jpg" alt="Hand-drawn circuit diagram. Shows the Gemma's Vout pin connected to a diode and vibration motor in parallel, with the diode backwards. They connect to the collector side of a transistor. The transistor's base is connected to the A0 pin on the Gemma, via a resistor. The emitter side of the transistor is attached to Gemma's Ground pin. The Gemma also has a section labeld JST that connects to a batter, and it also has an A2 pin labeled as "cap button"." /></p>
<p>It’s relatively simple. The motor connects to the the Vout pin, which is always the max voltage the battery or USB can give, then to a transistor, then to ground. The transistor is acting as a switch. Its base is connected to A0, which will be controlled by the code. When A0 is high, it’ll “close the switch” aka let the transistor connect the Vout to ground, causing electricity to flow through the motor and vibrate. The JST bit is the JST connector on the Gemma. I’ll use that to connect to my coin cell batteries, and it’ll be the power when the bracelet is on my wrist. The “cap button” is the A2 pin, which I’ll use as a capacitive button, allowing me to cycle through the time between vibrations.</p>
<blockquote>
<p><strong>Future Danielle note</strong>: all of my planning writeups have 3.3V as the battery voltage. This is incorrect, as I explain later, but the rest is correct to the best of my knowledge</p>
</blockquote>
<p>You’ll also see that diode sitting around, and it’s going the wrong way, to boot! I had to google around some to find a good answer for that, which I found at the <a href="http://www.learningaboutelectronics.com/Articles/Vibration-motor-circuit.php">Learning about Electronics website</a>:</p>
<blockquote>
<p>When driving a motor with a microcontroller such as the arduino we have here, it is important to connect a diode reverse biased in parallel to the motor. This is also true when driving it with a motor controller or transistor. The diode acts as a surge protector against voltage spikes that the motor may produce. The windings of the motor notoriously produce voltage spikes as it rotates. Without the diode, these voltages could easily destroy your microcontroller, or motor controller IC or zap out a transistor.</p>
</blockquote>
<p>So that prevents accidentally killing the Gemma, which I aprove of.</p>
<p>Now that I have a circuit planned, I have to figure out how to orient all the parts on the physical bracelet. I did a lot of drawing, but finally settled on a set up. Going from one side of the bracelet to the other, I’d have the vibration circuit, then the gemma, then the batteries. This way, I could have the vibration happen on the inside of my wrist, the gemma would be centered on the back of my wrist like a watch face, and the batteries would be out of the way of everything else.</p>
<p>The drawn version of what I mean:
<img src="/assets/adafruit-mindfulness-bracelet/drawing_orientation_of_circuit_on_bracelet.jpg" alt="Drawing of the organization of the bracelet as explained above" /></p>
<h4 id="putting-things-together">Putting Things Together</h4>
<p>This process is mainly where I remembered I don’t actually like hand-sewing that much, even though I can do it. There’s not much to say here, beyond I was simply following my planning, so this section is just a series of pictures of my work.</p>
<p>First step, I attach the Gemma to the nylon strap. I wanted to have it centered on the strap, so I put in two sewing pins to indicate where I wanted the gemma while the strap was on my wrist, then used those as reference when I sewed it on.
<img src="/assets/adafruit-mindfulness-bracelet/bracelet_adding_gemma.jpg" alt="black nylon strap with the gemma on it, there is black thread coming from the bracelet, attached to a sewing needle. There are two sewing pins on either side of the gemma" /></p>
<p>Now that it was on, I could orient the vibration circuit in the correct location and make sure my drawing was accurate:
<img src="/assets/adafruit-mindfulness-bracelet/bracelet_with_circuit_partially_on.jpg" alt="black nylon strap with gemma on it. The strap is on a table going up and down the frame. below the gemma is the vibration circuit, laid out but not connected" /></p>
<p>I then soldered together the vibration circuit:
<img src="/assets/adafruit-mindfulness-bracelet/just_vibe_circuit.jpg" alt="Image of the vibration motor, diode, transistor, and resistor all soldered together" /></p>
<p>Everything seemed good for the vibration circuit, but before I spent too much time on that, I wanted to make sure the battery set-up would work. The battery holder is a bit too wide to fit crosswise on the strap, but I didn’t want it to go lengthwise because it would flatten out the nylon strip and make it harder to wrap around my wrist. So I ended up bending the connectors on the battery holder down, and then sewing it on crosswise. It’s still a bit bigger than I wanted, but it works!</p>
<p>The bent clips on the battery holder:
<img src="/assets/adafruit-mindfulness-bracelet/battery_holder_with_bent_clips.jpg" alt="side view of the sewable battery holder. The leads are bent down so they are flush with the edges of the battery holder, instead of at 90 degrees" /></p>
<p>And this is with the sewn on battery holder and connection to the Gemma. You’ll note I’m only using one cell battery, when my hardware lists 2. Again, I’ll get to that in a bit. This is one of the places where I used my conductive thread! So instead of soldering the JST leads directly to the battery holder, I sewed the leads onto the strap, then used the conductive thread to attach to the battery. As a bonus, the thread helped the battery holder stay secure.
<img src="/assets/adafruit-mindfulness-bracelet/bracelet_with_battery_and_gemma.jpg" alt="black nylon bracelet with the gemma sewn on, and above it, the battery holder sewn on the strap crosswise" /></p>
<p>Lastly, I sew the vibration circuit onto the strap, and it’s completed!
<img src="/assets/adafruit-mindfulness-bracelet/bracelet_completed_with_one_battery.jpg" alt="nylon strap with all pieces sewn onto it" /></p>
<p>And a view on my wrist:
<img src="/assets/adafruit-mindfulness-bracelet/bracelet_complete_on_wrist.jpg" alt="nylon strap is now on my left wrist, you can see the Gemma on the back of my wrist, with the vibration circuit on the inside of my wrist" /></p>
<p>Now I’m ready to make it do stuff!</p>
<h3 id="software-side">Software Side</h3>
<p>The basic version of the software is available on the project page here: <a href="https://learn.adafruit.com/buzzing-mindfulness-bracelet/circuitpython-code">https://learn.adafruit.com/buzzing-mindfulness-bracelet/circuitpython-code</a>. But where’s the fun of leaving things so simple! Let’s do some mods.</p>
<blockquote>
<p><strong>Future Danielle note</strong>: This is a good example of me forgetting the KISS principle - <strong>K</strong>eep <strong>I</strong>t <strong>S</strong>imple, <strong>S</strong>tupid. While troubleshooting, I had to revert to the simpler version of the software repeatedly, because I didn’t fully understand the hardware side</p>
</blockquote>
<h4 id="cycling-through-intervals">Cycling Through Intervals</h4>
<p>The first change is allowing users to change how long the Gemma waits between vibrations. There isn’t an easy way to let users type in a given number of minutes, but there are some capacitive touch buttons you can use. So I added the ability to cycle through a collection of times: 1 minute, 5 minutes, 10 minutes, and an hour. I attached cycling through these options to the Pad #0/A2 on the Gemma, setup as a capacitive touch button. And when the user changes the timing, they need to know what timing they’ve changed it to, so I need to inform the end user somehow.</p>
<p>So for this, add a check if the capacitive touch button is set to true, meaning the user is touching it. Then, I have to update the interval timing. Here’s that change in psuedo-python:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"> <span class="n">on_time</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># Vibration motor run time, in seconds
</span> <span class="n">interval</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">intervalArray</span> <span class="o">=</span> <span class="p">[</span><span class="mi">60</span><span class="p">,</span> <span class="mi">300</span><span class="p">,</span> <span class="mi">600</span><span class="p">,</span> <span class="mi">3600</span><span class="p">]</span> <span class="c1">#interval options user can choose from
</span> <span class="n">intervalIndex</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="c1"># vibration turns on every interval seconds, for on_time seconds, non-blocking
</span>
<span class="k">if</span> <span class="n">touch</span> <span class="n">cap</span> <span class="n">button</span><span class="p">:</span>
<span class="n">intervalIndex</span> <span class="o">=</span> <span class="p">(</span><span class="n">intervalIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="n">mod</span> <span class="nb">len</span><span class="p">(</span><span class="n">intervalArray</span><span class="p">)</span>
<span class="n">interval</span> <span class="o">=</span> <span class="n">intervalArray</span><span class="p">[</span><span class="n">intervalIndex</span><span class="p">]</span></code></pre></figure>
<p>This lets me cycle through the array options, and once I get to the end of the array, looping back (that’s the mod bit)</p>
<blockquote>
<p><strong>NOTE</strong> mod, also represented as % means modulo, and it finds the remainder when you divide one number by another. E.g. if you divide 7 by 6 you’d get 1. A fun trick with modulo is that you can use it to keep an index value inside valid array indices without having to add <code class="language-plaintext highlighter-rouge">if</code> statements. If an array is 0-indexed, you can always do <code class="language-plaintext highlighter-rouge">index = (index + 1) % arrayLength</code> and the result will always be 0 to arrayLength-1, exactly the indices you need!</p>
</blockquote>
<h4 id="informing-the-user">Informing the User</h4>
<p>Now, I can change the time between vibrations, but I need to tell the user what I changed it to. I have a dotstar LED on the Gemma that I can flash at the user. One flash per minute seems pretty reasonable. Since I was using the dotstar, I had to include libraries on the Gemma. Adafruit has pre-built libraries you can download here: <a href="https://learn.adafruit.com/adafruit-gemma-m0/circuitpython-libraries">https://learn.adafruit.com/adafruit-gemma-m0/circuitpython-libraries</a>. You then copy the ones you need into the <code class="language-plaintext highlighter-rouge">lib</code> folder on the Gemma when it’s plugged into your computer. I ended up having to copy the <code class="language-plaintext highlighter-rouge">adafruit_dotstar</code> and <code class="language-plaintext highlighter-rouge">pypixelbuf</code> libraries. Look farther down under my “troubleshooting” section for an explanation of how I found the minimal required libraries.</p>
<p>So, the simple and naive version of informing users would be something like this (still in psuedo-python):</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"> <span class="n">on_time</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># Vibration motor run time, in seconds
</span> <span class="n">interval</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">intervalArray</span> <span class="o">=</span> <span class="p">[</span><span class="mi">60</span><span class="p">,</span> <span class="mi">300</span><span class="p">,</span> <span class="mi">600</span><span class="p">,</span> <span class="mi">3600</span><span class="p">]</span> <span class="c1">#interval options user can choose from
</span> <span class="n">intervalIndex</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="c1"># vibration turns on every interval seconds, for on_time seconds, non-blocking
</span>
<span class="k">if</span> <span class="n">touch</span> <span class="n">cap</span> <span class="n">button</span><span class="p">:</span>
<span class="n">intervalIndex</span> <span class="o">=</span> <span class="p">(</span><span class="n">intervalIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="n">mod</span> <span class="nb">len</span><span class="p">(</span><span class="n">intervalArray</span><span class="p">)</span>
<span class="n">interval</span> <span class="o">=</span> <span class="n">intervalArray</span><span class="p">[</span><span class="n">intervalIndex</span><span class="p">]</span>
<span class="c1"># alert user of new time!
</span> <span class="k">for</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span> <span class="n">to</span> <span class="n">interval</span><span class="o">/</span><span class="mi">60</span><span class="p">):</span>
<span class="n">dotstar</span> <span class="n">on</span>
<span class="n">sleep</span> <span class="k">for</span> <span class="p">.</span><span class="mi">25</span> <span class="n">seconds</span>
<span class="n">dotstar</span> <span class="n">off</span>
<span class="n">sleep</span> <span class="k">for</span> <span class="p">.</span><span class="mi">25</span> <span class="n">seconds</span></code></pre></figure>
<h4 id="minimizing-sleep">Minimizing Sleep</h4>
<p>If you write up the real python version of the psuedo code above and try it on your own project, you’ll see that it works! <em>But</em> there’s a bit of an issue there. It’s those sleep statements! If you do this, and say, set it to 10 minute intervals, that means the code is going to be in that <code class="language-plaintext highlighter-rouge">for</code> loop for 5 seconds. While it’s doing that, it’s not checking if it needs to vibrate or even change the interval again (say if a user wants to skip from 5 minutes to a half hour and skip the 10 minutes entirely).</p>
<blockquote>
<p><strong>NOTE</strong> How long the microcontroller takes for that <code class="language-plaintext highlighter-rouge">for</code> loop is straightforward calculation. Each single time through that <code class="language-plaintext highlighter-rouge">for</code> loop takes .25 seconds while the dotstar is on and .25 seconds while it’s off, for a total of .5 seconds per loop. Take that times the known 10 times it needs to flash equal 5 seconds. Now there’s also the time it takes for the dotstar to turn on and off, but it’s very likely the sleep calls vastly outweigh the time for the dotstar. Plus, the only way to speed up turning the dotstar on and off is to write my own dotstar library, but I can speed up by removing sleep calls much more easily.</p>
</blockquote>
<p>So I need to update the code so it isn’t blocking while flashing the dotstar.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"> <span class="n">on_time</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># Vibration motor run time, in seconds
</span> <span class="n">interval</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">intervalArray</span> <span class="o">=</span> <span class="p">[</span><span class="mi">60</span><span class="p">,</span> <span class="mi">300</span><span class="p">,</span> <span class="mi">600</span><span class="p">,</span> <span class="mi">3600</span><span class="p">]</span> <span class="c1">#interval options user can choose from
</span> <span class="n">intervalIndex</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="c1"># vibration turns on every interval seconds, for on_time seconds, non-blocking
</span>
<span class="k">if</span> <span class="n">touch</span> <span class="n">cap</span> <span class="n">button</span><span class="p">:</span>
<span class="n">intervalIndex</span> <span class="o">=</span> <span class="p">(</span><span class="n">intervalIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="n">mod</span> <span class="nb">len</span><span class="p">(</span><span class="n">intervalArray</span><span class="p">)</span>
<span class="n">interval</span> <span class="o">=</span> <span class="n">intervalArray</span><span class="p">[</span><span class="n">intervalIndex</span><span class="p">]</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">=</span> <span class="n">interval</span><span class="o">/</span><span class="mi">60</span>
<span class="k">if</span> <span class="p">(</span><span class="n">timesToTellUserAboutTiming</span> <span class="o">></span> <span class="mi">0</span><span class="p">):</span>
<span class="n">dotstar</span> <span class="n">on</span>
<span class="n">sleep</span> <span class="k">for</span> <span class="p">.</span><span class="mi">25</span> <span class="n">seconds</span>
<span class="n">dotstar</span> <span class="n">off</span>
<span class="n">sleep</span> <span class="k">for</span> <span class="p">.</span><span class="mi">25</span> <span class="n">seconds</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">-=</span> <span class="mi">1</span> </code></pre></figure>
<p>Adding a new global <code class="language-plaintext highlighter-rouge">timesToTellUserAboutTiming</code> variable lets me minimize how long the microcontroller is busy before it next checks if the cap button is touched. In this case, it will flash the dotstar once per <code class="language-plaintext highlighter-rouge">while True</code> loop, meaning the time between checking for button press is .5 seconds instead of potentially 5 or more. An order of magnitude of improvement, the best kind!</p>
<p>Now, if I wanted to get even LESS sleep, so it responds even snappier, I could add in interrupts or other fancier functionality. But by the time I got to this point in my project, I was starting to remember the KISS principle and left it as “good enough”.</p>
<h4 id="differentiating-hours-and-minutes">Differentiating Hours and Minutes</h4>
<p>This last step was a result of user testing (me, I was the user). While testing out button presses, I realized having the dotstar flash 60 times for hour intervals was just plain silly. I wasn’t going to count the flashes accurately past 10 or so, and it just took forever. So I decided to update the code one more time. This time, I updated it so that the color of the dotstar also carried info. If it was flashing blue, it was minutes, and green meant an hour.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"> <span class="n">on_time</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># Vibration motor run time, in seconds
</span> <span class="n">interval</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">intervalArray</span> <span class="o">=</span> <span class="p">[</span><span class="mi">60</span><span class="p">,</span> <span class="mi">300</span><span class="p">,</span> <span class="mi">600</span><span class="p">,</span> <span class="mi">3600</span><span class="p">]</span> <span class="c1">#interval options user can choose from
</span> <span class="n">intervalIndex</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">newTimingColor</span> <span class="o">=</span> <span class="n">blue</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="c1"># vibration turns on every interval seconds, for on_time seconds, non-blocking
</span>
<span class="k">if</span> <span class="n">touch</span> <span class="n">cap</span> <span class="n">button</span><span class="p">:</span>
<span class="n">intervalIndex</span> <span class="o">=</span> <span class="p">(</span><span class="n">intervalIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="n">mod</span> <span class="nb">len</span><span class="p">(</span><span class="n">intervalArray</span><span class="p">)</span>
<span class="n">interval</span> <span class="o">=</span> <span class="n">intervalArray</span><span class="p">[</span><span class="n">intervalIndex</span><span class="p">]</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">=</span> <span class="n">interval</span><span class="o">/</span><span class="mi">60</span>
<span class="n">newTimingColor</span> <span class="o">=</span> <span class="n">blue</span>
<span class="k">if</span> <span class="n">timesToTellUserAboutTiming</span> <span class="o">>=</span> <span class="mi">60</span><span class="p">:</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">/=</span> <span class="mi">60</span> <span class="c1"># convert to hours
</span> <span class="n">newTimingColor</span> <span class="o">=</span> <span class="n">green</span>
<span class="k">if</span> <span class="p">(</span><span class="n">timesToTellUserAboutTiming</span> <span class="o">></span> <span class="mi">0</span><span class="p">):</span>
<span class="n">dotstar</span> <span class="n">on</span> <span class="k">with</span> <span class="n">newTimingColor</span>
<span class="n">sleep</span> <span class="k">for</span> <span class="p">.</span><span class="mi">25</span> <span class="n">seconds</span>
<span class="n">dotstar</span> <span class="n">off</span>
<span class="n">sleep</span> <span class="k">for</span> <span class="p">.</span><span class="mi">25</span> <span class="n">seconds</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">-=</span> <span class="mi">1</span> </code></pre></figure>
<p>This time, I check if the <code class="language-plaintext highlighter-rouge">timesToTellUserAboutTiming</code> is greater or equal to 60, which would mean it’s an hour or longer interval. If so, change the color to green. Otherwise, keep it blue.</p>
<h4 id="final-code">Final Code</h4>
<p>With all of the above steps, I came out with the final product below. Note that there’s certainly room for improvement, with some cleanup to make it simpler/easier to read. But again, in the spirit of KISS, and the fact I hadn’t figured out how to write unit tests for this, I didn’t refactor and left it at the version I knew worked.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"> <span class="c1"># Mindfulness Bracelet sketch for Adafruit Gemma. Briefly runs
</span> <span class="c1"># vibrating motor (connected through transistor) at regular intervals.
</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">board</span>
<span class="kn">from</span> <span class="nn">digitalio</span> <span class="kn">import</span> <span class="n">DigitalInOut</span><span class="p">,</span> <span class="n">Direction</span>
<span class="kn">from</span> <span class="nn">analogio</span> <span class="kn">import</span> <span class="n">AnalogOut</span>
<span class="kn">from</span> <span class="nn">touchio</span> <span class="kn">import</span> <span class="n">TouchIn</span>
<span class="kn">import</span> <span class="nn">adafruit_dotstar</span>
<span class="n">debug</span> <span class="o">=</span> <span class="bp">False</span>
<span class="c1">#turn off the dotstar
</span> <span class="n">dotstar</span> <span class="o">=</span> <span class="n">adafruit_dotstar</span><span class="p">.</span><span class="n">DotStar</span><span class="p">(</span><span class="n">board</span><span class="p">.</span><span class="n">APA102_SCK</span><span class="p">,</span> <span class="n">board</span><span class="p">.</span><span class="n">APA102_MOSI</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">dotstar</span><span class="p">.</span><span class="n">brightness</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">dotstar</span><span class="p">.</span><span class="n">fill</span><span class="p">((</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">))</span>
<span class="c1"># vibrating disc mini motor disc connected on D2
</span> <span class="c1">#use as an analog out so can control how much the motor vibrates
</span> <span class="n">vibrating_disc</span> <span class="o">=</span> <span class="n">AnalogOut</span><span class="p">(</span><span class="n">board</span><span class="p">.</span><span class="n">A0</span><span class="p">)</span>
<span class="c1"># quarter power: 16384
</span> <span class="c1"># half power: 32768
</span> <span class="c1"># full power: 65535
</span> <span class="c1"># NOTE: the vibration amount depends on voltage in. If powered by USB,
</span> <span class="c1"># quarter power is about right. If powered by a single 3V watch battery,
</span> <span class="c1"># full power is the way to go
</span> <span class="n">vibrating_disc_on_value</span> <span class="o">=</span> <span class="mi">65535</span>
<span class="c1"># Built in red LED
</span> <span class="n">led</span> <span class="o">=</span> <span class="bp">False</span>
<span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
<span class="n">led</span> <span class="o">=</span> <span class="n">DigitalInOut</span><span class="p">(</span><span class="n">board</span><span class="p">.</span><span class="n">D13</span><span class="p">)</span>
<span class="n">led</span><span class="p">.</span><span class="n">direction</span> <span class="o">=</span> <span class="n">Direction</span><span class="p">.</span><span class="n">OUTPUT</span>
<span class="c1"># Capacitive touch on A2
</span> <span class="n">touch2</span> <span class="o">=</span> <span class="n">TouchIn</span><span class="p">(</span><span class="n">board</span><span class="p">.</span><span class="n">A2</span><span class="p">)</span>
<span class="n">on_time</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># Vibration motor run time, in seconds
</span> <span class="n">interval</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># Time between reminders, in seconds
</span> <span class="n">intervalArray</span> <span class="o">=</span> <span class="p">[</span><span class="mi">60</span><span class="p">,</span> <span class="mi">300</span><span class="p">,</span> <span class="mi">600</span><span class="p">,</span> <span class="mi">3600</span><span class="p">]</span> <span class="c1">#interval options user can choose from
</span> <span class="n">intervalIndex</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">newTimingColor</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">)</span>
<span class="c1"># Updates the number of flashes it needs to display to tell the user
</span> <span class="c1"># how many minutes between vibrations it has just been set to
</span> <span class="c1"># does not actually flash the LED in this function, instead uses tellUserNewTiming()
</span> <span class="c1"># to avoid sleeping and potentially missing more input and/or time to vibrate
</span> <span class="k">def</span> <span class="nf">setNewTiming</span><span class="p">():</span>
<span class="k">global</span> <span class="n">interval</span><span class="p">,</span> <span class="n">timesToTellUserAboutTiming</span><span class="p">,</span> <span class="n">newTimingColor</span>
<span class="n">interval</span> <span class="o">=</span> <span class="n">intervalArray</span><span class="p">[</span><span class="n">intervalIndex</span><span class="p">]</span>
<span class="n">timeInMinutes</span> <span class="o">=</span> <span class="n">interval</span><span class="o">/</span><span class="mi">60</span>
<span class="n">newTimingColor</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span> <span class="c1"># blue
</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">=</span> <span class="n">timeInMinutes</span>
<span class="k">if</span> <span class="n">timeInMinutes</span> <span class="o">>=</span> <span class="mi">60</span><span class="p">:</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">=</span> <span class="n">timeInMinutes</span> <span class="o">/</span> <span class="mi">60</span>
<span class="n">newTimingColor</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1"># green
</span> <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(.</span><span class="mi">3</span><span class="p">)</span> <span class="c1">#make sure it's clear a new time is being set
</span>
<span class="c1"># Checks if the dotstar still needs to flash to tell user about a newly set time interval
</span> <span class="c1"># between vibrations. If there's still flashes needed, it will flash and sleep
</span> <span class="k">def</span> <span class="nf">tellUserNewTiming</span><span class="p">():</span>
<span class="k">global</span> <span class="n">timesToTellUserAboutTiming</span>
<span class="k">if</span> <span class="p">(</span><span class="n">timesToTellUserAboutTiming</span> <span class="o">></span> <span class="mi">0</span><span class="p">):</span>
<span class="c1">#turn on for a short time
</span> <span class="n">dotstar</span><span class="p">.</span><span class="n">brightness</span> <span class="o">=</span> <span class="p">.</span><span class="mi">2</span>
<span class="n">dotstar</span><span class="p">.</span><span class="n">fill</span><span class="p">(</span><span class="n">newTimingColor</span><span class="p">)</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(.</span><span class="mi">25</span><span class="p">)</span>
<span class="c1">#turn off for a short time
</span> <span class="n">dotstar</span><span class="p">.</span><span class="n">brightness</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">dotstar</span><span class="p">.</span><span class="n">fill</span><span class="p">(</span><span class="n">newTimingColor</span><span class="p">)</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(.</span><span class="mi">25</span><span class="p">)</span>
<span class="n">timesToTellUserAboutTiming</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">def</span> <span class="nf">initialSetup</span><span class="p">():</span>
<span class="c1">#buzz some so you know it's awake!
</span> <span class="n">vibrating_disc</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">vibrating_disc_on_value</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(.</span><span class="mi">10</span><span class="p">)</span>
<span class="n">vibrating_disc</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(.</span><span class="mi">10</span><span class="p">)</span>
<span class="n">vibrating_disc</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">vibrating_disc_on_value</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(.</span><span class="mi">10</span><span class="p">)</span>
<span class="n">vibrating_disc</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(.</span><span class="mi">10</span><span class="p">)</span>
<span class="n">setNewTiming</span><span class="p">()</span>
<span class="n">initialSetup</span><span class="p">()</span>
<span class="n">interval</span> <span class="o">=</span> <span class="n">intervalArray</span><span class="p">[</span><span class="n">intervalIndex</span><span class="p">]</span>
<span class="n">start_time</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">monotonic</span><span class="p">()</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">timer</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">monotonic</span><span class="p">()</span> <span class="o">-</span> <span class="n">start_time</span>
<span class="k">if</span> <span class="n">timer</span> <span class="o">>=</span> <span class="n">interval</span> <span class="ow">and</span> <span class="n">timer</span> <span class="o"><=</span> <span class="p">(</span><span class="n">interval</span> <span class="o">+</span> <span class="n">on_time</span><span class="p">):</span>
<span class="n">vibrating_disc</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">vibrating_disc_on_value</span>
<span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
<span class="n">led</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="bp">True</span>
<span class="k">elif</span> <span class="n">timer</span> <span class="o">>=</span> <span class="p">(</span><span class="n">interval</span> <span class="o">+</span> <span class="n">on_time</span><span class="p">):</span>
<span class="n">vibrating_disc</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">if</span> <span class="n">debug</span><span class="p">:</span>
<span class="n">led</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="bp">False</span>
<span class="n">start_time</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">monotonic</span><span class="p">()</span>
<span class="c1"># use A2 as capacitive touch to cycle through interval options
</span> <span class="k">if</span> <span class="n">touch2</span><span class="p">.</span><span class="n">value</span><span class="p">:</span>
<span class="n">intervalIndex</span> <span class="o">=</span> <span class="p">(</span><span class="n">intervalIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">intervalArray</span><span class="p">)</span>
<span class="n">setNewTiming</span><span class="p">()</span>
<span class="n">tellUserNewTiming</span><span class="p">()</span></code></pre></figure>
<h4 id="troubleshooting-software">Troubleshooting Software</h4>
<p>Partway through my development, I somehow managed to reset the Gemma completely. It removed my code and libraries, and set it back to the default example it shipped with. I have no idea why. But happily (kind of),that meant I got to learn how to troubleshoot the Gemma some!</p>
<p>When it was reset to default, I first copied my code over. And then it just started blinking at me. As it turns out, adafruit includes a way of troubleshooting your code on the Gemma using just the dotstar. Their documentation here: <a href="https://learn.adafruit.com/adafruit-gemma-m0/troubleshooting">https://learn.adafruit.com/adafruit-gemma-m0/troubleshooting</a>, explains what different flashes mean.</p>
<blockquote>
<p>Colors with multiple flashes following indicate a Python exception and then indicate the line number of the error. The color of the first flash indicates the type of error:</p>
<p>GREEN: IndentationError</p>
<p>CYAN: SyntaxError</p>
<p>WHITE: NameError</p>
<p>ORANGE: OSError</p>
<p>PURPLE: ValueError</p>
<p>YELLOW: other error</p>
</blockquote>
<p>Once that happened, I knew I needed to connect to the REPL so I could see the error there. I’m on linux, and so used <a href="https://learn.adafruit.com/welcome-to-circuitpython/advanced-serial-console-on-mac-and-linux">https://learn.adafruit.com/welcome-to-circuitpython/advanced-serial-console-on-mac-and-linux</a> to get me to connect.</p>
<p>I ended up using this to connect with repl and see the error:</p>
<p><code class="language-plaintext highlighter-rouge">screen /dev/ttyACM0 115200</code></p>
<p>And the first error was:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>main.py output:
Traceback (most recent call last):
File "main.py", line 9, in <module>
ImportError: no module named 'adafruit_dotstar'
</code></pre></div></div>
<p>Ah! Since it was set to default, the libraries I had it in were gone. So I re-downloaded the libraries and copied over the <code class="language-plaintext highlighter-rouge">adafruit_dotstar</code> library. Now, I got a different error:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>main.py output:
Traceback (most recent call last):
File "main.py", line 9, in <module>
File "adafruit_dotstar.py", line 22, in <module>
ImportError: no module named 'adafruit_pypixelbuf'
</code></pre></div></div>
<p>Getting errors one at a time like this is kind of annoying. But! I copied over the <code class="language-plaintext highlighter-rouge">adafruit_pypixelbuf</code> library as well, and the code worked. Yay!</p>
<h3 id="putting-it-all-together">Putting it all together</h3>
<p>I now have the code! I now have the hardware! Now the big step, load up the code, then disconnect the USB and power it by battery!</p>
<p>…why is it suddenly blinking brown at me?</p>
<p>I restart it, same issue. I connect to USB, it works!</p>
<p>Hmmm. The biggest difference there is amount of power it gets. Uh oh, I may be misunderstanding some things…</p>
<h3 id="aside-understanding-battery-calculations">Aside: Understanding Battery Calculations</h3>
<p>I haven’t had much reason to learn battery calculations, aka figuring out what type of battery I need and how long they’ll last. I was a web developer previously, if your laptop dies while you’re looking at my site, that’s a you problem. But now, it was very much my problem!</p>
<p>Initially I had only one coin battery on my bracelet, leading to what I believe were brownouts, where the voltage dipped too low to support everything, and the microcontroller just complains at me. Since plugging it into USB works, I figure I need more juice. After double checking the adafruit docs, it turns out it needs 4-6 Volts.But one coin battery is 3.3. Why then does the initial project have a 3.7V battery? No idea. But let’s see if I can hack something together. I remember you can increase voltage by connecting batteries…somehow. Some googling proved I can connect two coin batteries in series to increase the voltage amount: <a href="https://www.power-sonic.com/blog/how-to-connect-batteries-in-series-and-parallel/">https://www.power-sonic.com/blog/how-to-connect-batteries-in-series-and-parallel/</a>. I do this by connecting the negative terminal on one to positive of the other. The free positive and free negative attach to the microcontroller. I used the multimeter to check the voltage before I connect to the microcontroller, and it was 5.98V, which was perfect! I gave it a whirl, and it works! But the thing is, I wasn’t entirely sure why. I googled around more, but only got more confused.</p>
<p>I took to the local makerspace’s slack, and got some lovely people to explain the concepts to me. After talking through my project and some general guidelines for calculating battery things, I came out with the following.</p>
<p><strong>For figuring out voltage needed</strong> I go through all the parts in my circuit and figure out their voltage range (i.e. look at the docs). I then make sure the voltage I provide is either inside the range of all parts, or add a part that changes the voltage before it gets to the sensitive bits, so nothing blows up.</p>
<p><strong>For figuring out how long the batteries last for a circuit I haven’t built yet</strong> I’d take all power-hungry parts in the circuit, add up their current usage, make sure it’s the same units as the battery’s hour unit (e.g. make sure it’s mA if the battery has 200mAh), and divide the mAh by the summed up mA (plus a bit for fudge factor), and that gives me a rough time it’ll live.</p>
<p><strong>For figuring out how long the batteries last for a circuit I have built</strong> use a multimeter in series with the circuit, make sure I use the right setting to prevent tripping the fuse, and it’ll show me the current current (har har) usage. Then divide the battery mAh by the current I see on the multimeter, and I get the rough time it’ll live.</p>
<h4 id="battery-calculations-for-the-bracelet">Battery Calculations for the Bracelet</h4>
<p>Since I have this newfound knowledge, let’s put it to good use! First step: figure out voltage. I do that by looking at all parts of my circuit, and reading their docs. My schematic-reading abilities came in handy for this, because the Gemma M0 is a microcontroller, plus other parts, so I couldn’t just rely on knowing the microcontroller and going from there. Happily, Adafruit puts out the schematic info, so I could look at it, and then google part numbers to find out what each part did.</p>
<p>The Gemma M0 is broken down into individual parts as understood from schematic here: <a href="https://cdn-learn.adafruit.com/assets/assets/000/044/361/original/gemma_schem.png?1501106076">https://cdn-learn.adafruit.com/assets/assets/000/044/361/original/gemma_schem.png?1501106076</a>. I also include the vibration motor, the only other power-hungry part in my circuit.</p>
<table>
<thead>
<tr>
<th>part No.</th>
<th>Part Type</th>
<th>voltage range</th>
<th>current use</th>
<th>Datasheet</th>
</tr>
</thead>
<tbody>
<tr>
<td>ATSAMD21E18</td>
<td>32-bit ARM Cortex -M0+ processor</td>
<td>1.62V – 3.63V</td>
<td>3.11 - 3.64 mA</td>
<td><a href="https://cdn-learn.adafruit.com/assets/assets/000/044/363/original/samd21.pdf?1501106093">https://cdn-learn.adafruit.com/assets/assets/000/044/363/original/samd21.pdf?1501106093</a></td>
</tr>
<tr>
<td>ap211k-3.3</td>
<td>CMOS process low dropout linear regulator</td>
<td>2.5V-6.0V</td>
<td>55µA when quiescent aka .055mA</td>
<td><a href="https://www.diodes.com/assets/Datasheets/AP2112.pdf">https://www.diodes.com/assets/Datasheets/AP2112.pdf</a></td>
</tr>
<tr>
<td>AP102-2020</td>
<td>APA102 IC for the three-color RGB Dimming control strip and string</td>
<td>.3-6V</td>
<td>.1W-.5W aka 20mA-100mA according to <a href="https://www.rapidtables.com/calc/electric/Watt_to_Amp_Calculator.html">this watt to amp calculator</a></td>
<td><a href="https://cdn-shop.adafruit.com/product-files/3341/3341_APA102-2020+SMD+LED.pdf">https://cdn-shop.adafruit.com/product-files/3341/3341_APA102-2020+SMD+LED.pdf</a></td>
</tr>
<tr>
<td>100614</td>
<td>Vibration motor</td>
<td>2.5~3.8V (adafruit site says 2V - 5V)</td>
<td>75 mA max (adafruit site has a larger range depending on voltage, from 40mA-100mA)</td>
<td><a href="https://cdn-shop.adafruit.com/product-files/1201/P1012_datasheet.pdf">https://cdn-shop.adafruit.com/product-files/1201/P1012_datasheet.pdf</a></td>
</tr>
</tbody>
</table>
<p><strong>Voltage Calculation</strong></p>
<p>Looking through all of this, the voltage needs to be between 2.5 and 6 volts. And the vibration motor needs only 5V. Right now, it’s connected to Vout, which is supposed to be the max power the Gemma M0 is receiving. So it may actually be getting 5.98V right now. Since it hasn’t blown up yet, it must be able to handle that, but I may need to update how that connects so I don’t prematurely wear it out.</p>
<p><strong>Current calculation</strong></p>
<p>For the parts that are potentially running all the time, I just need to get the max current use for each of them, aka the SAMD21 and the linear regulator.</p>
<p>For the vibration motor, because I’m turning it on and off for brief time periods, I don’t want to just add the current it uses when on to the total amount, because it’s only on for short times. So I need to calculate the duty cycle (percentage of time it’s pulling current over a given cycle). So if it buzzes for one second every minute, that’d be 1/60, aka it’s on 1.66% of the time. So if it’s drawing 100mA cuz I’m giving it 5V, that means on average it’s drawing 100mA*(1sec/60sec), aka 1.67mA.</p>
<blockquote>
<p><strong>NOTE</strong> Duty cycle is the percentage a part is on and drawing power, for a given cycle</p>
</blockquote>
<p>I have to also do this for the IC that controls the dotstar LEDs (part no. AP102-2020 in above table). This one has a max of 100mA current as well. In code, I’m turning on LEDs for a quarter of a second, to display info to end users. To keep it simple, I’ll pretend the user wants to change the interval timing every 10 minutes. If it’s flashing the max times (10 times for 10 minutes), then it’ll be on for 5 seconds every 10 minutes. Or 5/600, aka 0.00833, or .83% of the time. That means it’s average current use is about .83mA</p>
<p>Current use (taking the max current usage for some leeway) is:</p>
<p>(max current of SAMD21) + (max current of linear regulator) + (average current of dotstar RGB IC) + (average current of vibration motor)</p>
<p>=3.64 mA + .055mA + .83mA + 1.67mA</p>
<p>=6.195 mA</p>
<p>If the battery is 220mAh, then with this circuit, the batteries will last 220mAh/6.195mA = 35.51251008 hours</p>
<p>Cool! That’s certainly not a ton of time, since this would theoretically be on all day, but it’s still way more than I expected. I honestly figured with my luck the math would work out to be an hour or something.</p>
<p>Now, I wanted to verify all this math with some measurements using my multimeter. I go to try, and….the Gemma errors out on me. I reset it. Same thing. Welp. Guess I won’t be solving this in <em>this</em> blog post! And I was so close!</p>
<p>Before I tried to do the battery calculations, I had actually test-driven the watch. I wore it for a half hour or so, and it worked great! My suspicion is that something is using more power than I think, and it’s draining the batteries. But I’ve used up all my coin cell batteries already, so I won’t be able to probe the circuit with the multimeter to find the high power usage! I’ll have to pick up more batteries next time I’m at the store, and try again then. But for now, I think this blog post has come to an end. Not the triumph I had envisioned, but a hard-fought battle with a lot of new concepts.</p>
<h3 id="conclusion">Conclusion</h3>
<p>This project was a lot more work than what I thought “a simple embedded project” should be. But I learned a lot more about:</p>
<ul>
<li>troubleshooting with multimeters</li>
<li>transfering a circuit schematic from a drawing to real-life</li>
<li>how to calculate battery life</li>
<li>coming up with alternative ideas to communicate to users</li>
<li>the importance of avoiding sleep (the function, not the real-live version)</li>
</ul>
<p>Which was honestly the goal, more than a working mindfulness bracelet. I’ll continue working on this, and hopefully figure out the latest issue, and post talking about that. I may also look into transferring my functionality from CircuitPython to C and see if I can get that onto the Gemma.</p>
<p>Ultimately I think the defeat was mainly from biting off more than I can chew (aka forgetting to KISS). Making my first custom embedded project use batteries made it a lot more complicated that it would have been otherwise, and modifying the battery I use for it was definitely a mistake. Learning things is best done using +1 steps, learning just one new thing each time, but I was too excited and tried about a +10 instead.</p>
<p>I haven’t given up on this project yet, but I may let it sit back burner as I work on other projects. I finished a unit testing course that I want to apply to a project, and I want to do more STM32 work. The frustrations of this mindfulness bracelet have defeated me for now (which is more than a little ironic), but not forever.</p>
<h3 id="resources">Resources</h3>
<p>The original project: <a href="https://learn.adafruit.com/buzzing-mindfulness-bracelet/overview">https://learn.adafruit.com/buzzing-mindfulness-bracelet/overview</a></p>
<p>This troubleshooting page explains any blinking dotstar errors you may come across: <a href="https://learn.adafruit.com/adafruit-gemma-m0/troubleshooting">https://learn.adafruit.com/adafruit-gemma-m0/troubleshooting</a></p>
<p>Follow this to connect with repl and see errors when the Gemma is attached to your computer: <a href="https://learn.adafruit.com/welcome-to-circuitpython/advanced-serial-console-on-mac-and-linux">https://learn.adafruit.com/welcome-to-circuitpython/advanced-serial-console-on-mac-and-linux</a></p>
<p>Learning about Electronics website <a href="http://www.learningaboutelectronics.com/Articles/Vibration-motor-circuit.php">http://www.learningaboutelectronics.com/Articles/Vibration-motor-circuit.php</a></p>Setting up Blinky on various microcontrollers is one thing, actually having a working embedded system is another. So, I decided I needed something relatively easy, that preferably used what I had around already, and used the conductive thread that I had recently gotten from Adafruit as a present. After some thinking, I came across a simple idea: I’ve been stressed a lot recently, and my back has been storing that all in the form of painful knots. So how about I made something that let me remember to relax my back throughout the day! I didn’t want to have yet another app sending notifications, so how about something that buzzed, maybe a wearable watch? I did some googling, and came upon the Adafruit mindfulness bracelet. I already had the Gemma M0, and I could use conductive thread to sew the circuit onto a simple nylon bracelet. AND the code was obviously really simple, just wait a minute or two, then vibrate, then wait. It would be a simple and quick project to dip my toes into full embedded systems! Or so I thought.Getting started with STM32 black pill - Getting blinky with STM32Cube IDE2021-06-16T00:00:00+00:002021-06-16T00:00:00+00:00/blog/2021/6/16/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide<p>Now that I’ve dipped my toes into the microcontroller world, lets cannonball in with the world of STM32 microcontrollers. There’s a <em>ton</em> of different microcontrollers that are all STM32, but I’ll be starting with a relatively easy starting microcontroller. It’s easy because it comes on a cheap development board that doesn’t require any custom PCB work, and it has a funny nickname. I’m talking about the We Act Studio’s STM32F411 dev board, nicknamed the “Black Pill”. It lets me start figuring out the embedded toolchain immediately, without having to dive too deep into the hardware side. Though I’ll still be looking at schematics, since they’re important and it’s good practice.</p>
<p>The company that makes STM32 microcontrollers is called STMicroelectronics, though later in this post I’ll just refer to them as ST. And happily, they have developed a lot of software and support for the STM32, so hopefully, it’ll be a pretty easy process to ge the toolchain set up.</p>
<p>Going back to the Embedded For Everyone wiki <a href="https://github.com/nathancharlesjones/Embedded-for-Everyone/wiki/1.-Getting-to-%22Blinky%22-with-a-new-MCU">https://github.com/nathancharlesjones/Embedded-for-Everyone/wiki/1.-Getting-to-%22Blinky%22-with-a-new-MCU</a>, there’s a nice graphic that shows all parts of an embedded system toolchain. AKA all the bits needed to actually program and debug a microcontroller. I annotated it with what I’m going to use, to give kind of an overview of my whole toolchain.</p>
<p><img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/Embedded-toolchain-full.png" alt="Drawing representing the embedded toolchain. It is a simplified, visual version of the list below this image." /></p>
<p>Lets go a little more in-depth about these pieces.</p>
<ol>
<li><strong>The MCU</strong> - this is the STM32F411 microcontroller that is on the Black pill board</li>
<li><strong>Serial Wire Debug (SWD)</strong> - I’ll talk to it via the SWD header that’s on the Black pill board</li>
<li><strong>Debug adaptor</strong> - this is the ST-link v2. It connects to the SWD header on the black pill, and has a USB plug to let it talk to the computer. Everything after this in this list is software. The only bits of hardware needed are the Black pill and this ST-link v2!</li>
<li><strong>The IDE</strong>- this contains all the software and packages I need to talk to the black pill. I’ll be using the STM32Cube IDE. It contains the following sub-systems
<ol>
<li><strong>Adaptor Driver</strong> - this talks with the st-link v2 via USB. It can send code (aka the ST-link is a programmer), and can also talk with the MCU directly to do debugging(so the ST-link is also a debugger). It supports both the ST-link v2, and also J-link, an alternative debugger hardware.</li>
<li><strong>Code Editor</strong> - this is the actual place I write my code. It’s based on Eclipse, a popular IDE, and according to ST’s website, can support Eclipse plugins</li>
<li><strong>Middleware</strong> - this is all the code written by ST to make programming STM32 microcontrollers easier. ST calls them STM32cube MCU/MPU packages. These include the Hardware Abstraction Layer (HAL), Low-Layer (LL) APIs, and various libraries to support things like Real-time operating systems (RTOS), USB, file systems, etc. It also has a GUI that helps you with your initial setup of the different pins of a microcontroller. E.g. setting a particular pin to be a GPIO output pin. The STM32Cube IDE has packages for each of the STM32 families it supports. It’s a lot of code</li>
<li><strong>Compiler/linker</strong> - this is the ARM GCC toolchain. This is the bit that actually compiles your C code into something the STM32 ARM microcontroller can actually run</li>
<li><strong>Debug software</strong> - the STM32Cube IDE supports using GDB as the debugger, which is a common C debugger tool. It also has extra debug support, like supporting RTOS debugging.</li>
</ol>
</li>
</ol>
<h3 id="the-hardware-side">The Hardware Side</h3>
<p>There’s apparently a lot of places to get the hardware side, and for relatively cheap. But a lot of the places seem to be “Aliexpress” and “Ebay”, and it feels like the quality control and speed of delivery for those both can be lacking. So instead, since I buy so much from Adafruit anyway, I decided to get my software from there.</p>
<p>As I mentioned above, I only need two bits of hardware, the black pill itself, and the debugger/programmer ST-link. The ST-link even comes with the right female-to-female jumper wires so I can connect the two together. Below are the links to adafruit for the hardware I had to order.</p>
<ul>
<li>ST-link V2 from adafruit: <a href="https://www.adafruit.com/product/2548">https://www.adafruit.com/product/2548</a></li>
<li>We Act Studio STM32F411 “BlackPill” Development Board <a href="https://www.adafruit.com/product/4877">https://www.adafruit.com/product/4877</a></li>
</ul>
<p>Once I got them, I need to connect them together. The black pill from adafruit comes with header pins that aren’t soldered on, so I had to do some light soldering to get the SWD pins and the header pins connected up.</p>
<p><img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/soldering headers.jpg" alt="black pill PCB attached to a third hand tool to keep it steady while I solder. The SWD header is put into the board, and has 4 wires connected to it" /></p>
<p>I used my third hand to keep the board and SWD header pins steady while I soldered it up. I also attached the female jumper wires to the SWD pins, to make sure I didn’t solder the pins too close to the PCB board. After I this, I soldered on the headers that run down each side of the black pill, and used the trick of attaching it to a breadboard, so the pins are properly straight while I solder.</p>
<p>With the pins all on, I need to connect the st-link and the black pill together. Happily, the st-link v2 has the pinout for its connections right on it’s casing, so I don’t need to lookup the pinouts online. The black pill has what each SWD header pin is connected to screenprinted on the board as well. So it’s a matter of connecting the included female-to-female jumper cables to the correct pins on each. They each call the pins something slightly different, but it’s pretty easy to guess which goes to which. Since this is SWD communication, you just connect each pin that’s named the same together. This is different than more tricky connections, like UART, which requires you to connect the Rx pin to the Tx of the other device and vice versa.</p>
<p>Here’s a table of the pin connections from the Black pill to the st-link. They’re in order for the black pill’s pins from top to bottom if the SWD header is facing to the right. I list the wire color because that’s helpful to track when you’re connecting them together, but the wires are not different in any way beyond coloring.</p>
<table>
<thead>
<tr>
<th>Black Pill Pin</th>
<th>Wire Color</th>
<th>ST-link pin</th>
</tr>
</thead>
<tbody>
<tr>
<td>GND</td>
<td>Grey</td>
<td>GND</td>
</tr>
<tr>
<td>SCK</td>
<td>Blue</td>
<td>SWCLK</td>
</tr>
<tr>
<td>DIO</td>
<td>Purple</td>
<td>SWDIO</td>
</tr>
<tr>
<td>3.3V</td>
<td>White</td>
<td>3.3V</td>
</tr>
</tbody>
</table>
<p>And below is a picture of the final connection.</p>
<p><img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/connecting black pill and st link.jpg" alt="black pill and the st-link are connected with 4 colored jumper wires. the wires connect in the same way listed in the table above" /></p>
<p>Once connected, I plugged the ST-link’s USB into my computer, and success! No magic smoke escaped, and the power button lit up on the black pill. It’s now ready to program.</p>
<h3 id="the-software-side">The Software Side</h3>
<p>I’m using the STM32Cube IDE, which is nice because it’s all in one package to download. Download the IDE from: <a href="https://www.st.com/en/development-tools/stm32cubeide.html">https://www.st.com/en/development-tools/stm32cubeide.html</a>. There’s a version for Mac, Windows, and Linux.</p>
<p>I haven’t used this IDE package much yet, so I can’t give a recommendation on it one way or another. From what little I’ve done on it, it feels very much the classic “you can do everything here, but first you have to find the button for it” sort of IDE that’s very popular. E.g. Visual Studio, Eclipse, Netbeans, that sort of thing. There’s a lot of useful functionality, but it comes at the cost of complexity.</p>
<p>Also, because it’s based on Eclipse, which is Java-based, it can be pretty hefty and a bit of a strain on your system. I’ve already had issues with it hanging on my laptop. I’m not sure if this is because I’m running the Linux version, and it’s less supported than the windows/mac versions, or if it’s a common symptom of the STM32Cube IDE in general, or my computer just doesn’t like linux. Regardless, I had to get a book out to read while the IDE thought about various steps in my intitial set-up.</p>
<p>My eventual plan is to build out a more light-weight toolchain, potentially using docker to wrap all the dev tools up in one location. I liked the ATmega328p toolchain, that just used the compiler and avrdude to send to the chip, and I’d like to build out a similar toolchain for the black pill. But until then, let’s move on to writing some code.</p>
<h3 id="the-code">The Code</h3>
<p>Since I’m using ST’s recommended software, and it has everything but the kitchen sink, most of the work getting this project set up is clicking things inside the GUI. If I create a new project and tell the IDE what MCU I’m using, it will auto-generate all the setup code needed for me. So instead of adding in headers and setting individual pins to output, I just click on things.</p>
<h4 id="setup-steps">Setup Steps</h4>
<ol>
<li>Open up STM32Cube IDE, select File -> New -> STM32 Project</li>
<li>In the MCU/MPU Selector, enter “STM32F411CEU” into the search. This is the full name of the MCU on the adafruit black pill board. Select the only result in the search results, and click next
<img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/STM32Cube IDE MCU selector with Black Pill MCU selected.png" alt="STM32Cube IDE with MCU/MPU selector open" /></li>
<li>In the project setup popup, set the project name (In my case, I chose “Blinky”), leave the rest as default, so click next, then finish.</li>
<li>Once that’s done, it will open up the pinout and configuration page. There it’ll display the physical shape of the MCU, and the pins and pin names. This is where you can set individual pins to different default values, and the IDE will use this info to auto-generate setup code. In our case, we want to just left-click the <code class="language-plaintext highlighter-rouge">PC13</code> pin, and click “GPIO_Output”. This pin is the pin connected to a user-controlled LED on the black pill. If you look on the black pill, you can see the LED we want to control, and see it has <code class="language-plaintext highlighter-rouge">C13</code> next to it. Eventually we can set other pins to use more of the black pill’s dev board, but for now, that’s all we need to make blinky run.
<img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/STM32Cube IDE MCU configuration.png" alt="STM32Cube IDE MCU configuration page" />
MCU configuration page
<img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/STM32Cube IDE MCU configuration - left click pc13.png" alt="STM32Cube IDE MCU configuration page after left-clicking" />
Left-clicking the PC13 pin
<img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/STM32Cube IDE MCU configuration with pc13 as GPIO_output.png" alt="STM32Cube IDE MCU configuration page with PC13 set to GPIO_output" />
What the MCU configuration page looks like when PC13 is set to output</li>
<li>To have the IDE generate code, click the save icon, or hit <code class="language-plaintext highlighter-rouge">ctrl+s</code> to save the configuration. It will ask if you want to generate code, and then ask if you want to open the code perspective. Click yes to both.</li>
<li>Now the main.c file will be open in one of the tabs. Select it. This is finally some C code!</li>
<li>Scroll down to the <code class="language-plaintext highlighter-rouge">while(1)</code> section. This section is equivalent to the <code class="language-plaintext highlighter-rouge">loop()</code> function in arduino. Here we can add our code to turn the <code class="language-plaintext highlighter-rouge">PC13</code> pin on and off.
<img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/STM32Cube IDE main c file open.png" alt="STM32Cube IDE main.c file open" /></li>
</ol>
<p>Oof that’s a lot of clicking before we can even write a single line of C code! But we’re finally here. Now last time, with the ATmega328p, I didn’t use any libraries, and instead directly referenced registers in memory and did the appropiate bit-twiddling to get it to change the pin I needed. This time, I’m going the more “proper” way, and actually using libraries. Libraries let you abstract out specific implementations of different functionality, making your code (arguably) easier to read, and more portable. In this case, I’m using ST’s Hardware Abstraction Library (HAL), to set my pin to low, wait a second, then set it to high.</p>
<p>The calls I need to make are to <code class="language-plaintext highlighter-rouge">HAL_GPIO_WritePin()</code> and <code class="language-plaintext highlighter-rouge">HAL_Delay()</code>. The <code class="language-plaintext highlighter-rouge">HAL_GPIO_WritePin</code> function takes which register (in this case, <code class="language-plaintext highlighter-rouge">C</code>), which specific pin (<code class="language-plaintext highlighter-rouge">13</code>), and if I want it high or low (<code class="language-plaintext highlighter-rouge">0</code> or <code class="language-plaintext highlighter-rouge">1</code>). The <code class="language-plaintext highlighter-rouge">HAL_Delay</code> acts similar to the arduino <code class="language-plaintext highlighter-rouge">delay</code> function, and accepts a number, in milliseconds, of how long to delay.</p>
<blockquote>
<p><strong>NOTE</strong> I belive that comment on <code class="language-plaintext highlighter-rouge">HAL_Delay</code> is not technically true. I left the default clock settings, so the MCU is running at that speed. I suspect the <code class="language-plaintext highlighter-rouge">HAL_Delay</code> is not timing it to milliseconds, but rather to clock cycles. I haven’t confirmed this, however. And treating it as milliseconds-ish seems to work well enough for a blinky example</p>
</blockquote>
<p>Using this info, I can type in the <code class="language-plaintext highlighter-rouge">main.c</code> file and finally have my blinky example! STM32Cube IDE has auto-complete that lets me type my (very little) code faster, you can use it by starting to type a function, then <code class="language-plaintext highlighter-rouge">ctrl+space</code> to open the auto-complete options. Use the arrow keys to tab down the list, and click enter when you’re on the function you want.</p>
<blockquote>
<p><strong>NOTE</strong> The code you write should be between comments in main that say <code class="language-plaintext highlighter-rouge">USER CODE BEGIN</code> and <code class="language-plaintext highlighter-rouge">USER CODE END</code>. These comments let you know where to write your custom code, while still being able to use the MCU configuration to auto-generate code. If you want to change or add pin configurations in the MCU configuration page, any code written between a user code begin and end will be kept, but anything outside those comments will be overwritten. There’s a lot of different user code sections throughout the <code class="language-plaintext highlighter-rouge">main.c</code> file, so any custom code you want can be written wherever you’d like.</p>
</blockquote>
<h4 id="final-code">Final code</h4>
<p>So the final code inside the while loop, for a simple blinky using the STM32CubeIDE with the We Act STM32F411 “black pill”:</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"> <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">HAL_GPIO_WritePin</span><span class="p">(</span><span class="n">GPIOC</span><span class="p">,</span> <span class="n">GPIO_PIN_13</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">HAL_Delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="n">HAL_GPIO_WritePin</span><span class="p">(</span><span class="n">GPIOC</span><span class="p">,</span> <span class="n">GPIO_PIN_13</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">HAL_Delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="cm">/* USER CODE END WHILE */</span>
<span class="cm">/* USER CODE BEGIN 3 */</span>
<span class="p">}</span></code></pre></figure>
<p>Note that I’m setting pin 13 to 0 to turn it ON, and 1 to turn it OFF. If you don’t believe me, try changing the delay after the first <code class="language-plaintext highlighter-rouge">WritePin</code> to <code class="language-plaintext highlighter-rouge">5000</code> and see if it stays on or off longer. This is a result of how the LED is wired on the black pill board. If you look at the schematics for the board, you can see that the LED circuit is actually connected to 3.3 volts, then a resistor, then the LED, then PC13. This means when PC13 is low (set to <code class="language-plaintext highlighter-rouge">0</code>), it acts as ground, and electricity moves through the circuit.</p>
<p><img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/black pill LED schematic.png" alt="screenshot of the We Act Black Pill schematic, specifically the LED circuit attached to pin 13" /></p>
<p>This is a screenshot of the schematic diagram that adafruit gives here: <a href="https://cdn-shop.adafruit.com/product-files/4877/4877_schematic-STM32F411CEU6_WeAct_Black_Pill_V2.0.pdf">https://cdn-shop.adafruit.com/product-files/4877/4877_schematic-STM32F411CEU6_WeAct_Black_Pill_V2.0.pdf</a>. It shows two LEDs, the bottom one is the power LED, and other is the user-controlled LED on pin 13.</p>
<blockquote>
<p>As an aside, since a lot of hardware comes from China, I kind of wish I was learning Chinese as well as Japanese, so I could read their data sheets easier! Always more to learn, never enough time…</p>
</blockquote>
<h3 id="sending-the-code">Sending the code</h3>
<p>Finally, everything is coming together! Now that the STM32Cube IDE is all set up, we need to actually send the code to the black pill. This is happily, very easy. Plug in the ST-link v2 to your computer, make sure it’s connected to the black pill (the power pin should turn on), and click the green right arrow in the IDE. This will open the build configuration. You can leave that as default and click next. And it should send the code over!</p>
<h4 id="firmware-updates">Firmware updates</h4>
<p>When I attempted to do this the first time, STM32Cube IDE popped up a warning the firmware on my ST-link v2 was out of date and asked me to update it. I’m easily swayed by pop-up messages, so I did. Since nothing seemed to break from me doing that, I recommend allowing it to update.</p>
<p><img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/STMCubeIDE asking if I want to update firmware.png" alt="Popup asking me to update firmware" />
The first pop-up</p>
<p><img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/STM32Cube IDE ST-link firmware update popup.png" alt="Pop up that displays firmware info and an 'update' button" />
The firmware update pop-up</p>
<p><img src="/assets/getting-started-with-stm32-black-pill-getting-blinky-with-stm32cube-ide/STM32Cube IDE ST-link firmware update popup after update.png" alt="Pop-up after the update was finished" />
And the result after a successful update</p>
<p>Finally, after a lot of set-up, we get blinky! The <a href="https://github.com/nathancharlesjones/Embedded-for-Everyone/wiki/1.-Getting-to-%22Blinky%22-with-a-new-MCU">Embedded For Everyone Wiki</a> has a good image to represent my general state after getting it working.</p>
<p><img src="https://github.com/nathancharlesjones/Embedded-for-Everyone/raw/master/Supporting-documents/Behold%20My%20Blinky%202%2C%20PNG.png" alt="3-panel comic. First panel has someone fiddling with a breadboard angrily and asking why they're even doing this. Second panel shows them suprised and happy that it works. Third panel is the largest and shows the same person standing on a mountaintop, holding aloft a sword, without a shirt, showing off their muscle-y figure. There are skulls and bones on the mountaintop. They are surrounded by text that says 'Behold my blinky, cower before my might'" /></p>
<h3 id="conclusion">Conclusion</h3>
<p>Hopefully if you’re following along, at this point you’ll have a working blinky example. If you want to continue with STM32Cube IDE and ST’s HAL, this is the point where you start learning common HAL functions and building prototypes with it. You can also go back to the MCU configuration page and set more pins, like the external clock, and the user-controlled button. Now, I’m ambivalent about the HAL, but I frankly dislike the IDE. It feels like it’s hiding too much of the nitty gritty. And it’s repeated hanging while switching between the MCU configuration and the C code is an absolute deal-breaker. So my next steps will be attempting to get blinky with a different, hopefully simpler toolchain.</p>
<p>I’m also starting an embedded systems unit testing class on udemy, so I may also incorporate some testing frameworks in my next setup, since a project without tests is a side-project, not something for production.</p>Now that I’ve dipped my toes into the microcontroller world, lets cannonball in with the world of STM32 microcontrollers. There’s a ton of different microcontrollers that are all STM32, but I’ll be starting with a relatively easy starting microcontroller. It’s easy because it comes on a cheap development board that doesn’t require any custom PCB work, and it has a funny nickname. I’m talking about the We Act Studio’s STM32F411 dev board, nicknamed the “Black Pill”. It lets me start figuring out the embedded toolchain immediately, without having to dive too deep into the hardware side. Though I’ll still be looking at schematics, since they’re important and it’s good practice.Programming an ATmega328p without the Arduino IDE2021-06-08T00:00:00+00:002021-06-08T00:00:00+00:00/blog/2021/6/8/programming-an-atmega328p-without-the-arduino-ide<p>Now that I have an AVR programmer and the ATmega328p on its own breadboard (as I documented <a href="/blog/2021/5/25/directly-programming-an-atmega328p-from-an-arduino-uno">here</a>), I want to remove my dependence on the Arduino IDE download. So no more using tools that arduino IDE downloaded for me! My rough plan is as follows:</p>
<ol>
<li>pick a different IDE for writing my code</li>
<li>either write C code without any AVR-specific libraries, or find a SDK</li>
<li>download avr-gcc so I can compile my code</li>
<li>download AVRdude so I can send my compiled code to the ATmega328p</li>
<li>figure out if there’s any other things I have to download or run?
<!--more--></li>
</ol>
<p><br /></p>
<hr />
<p><strong><em>This is a part of my series on programming atmega328p</em></strong></p>
<p>For more posts on this, see below</p>
<ol>
<li>
<a href="/blog/2021/5/25/directly-programming-an-atmega328p-from-an-arduino-uno">Directly Programming an ATmega328p from an Arduino Uno</a>
</li>
<li>
<a href="/blog/2021/6/8/programming-an-atmega328p-without-the-arduino-ide">Programming an ATmega328p without the Arduino IDE</a>
(You are Here)
</li>
</ol>
<hr />
<p><br /></p>
<blockquote>
<p><strong>Note</strong> - this is all done on an Ubuntu machine, so instructions are for linux, not windows</p>
</blockquote>
<p>According to the <a href="https://github.com/nathancharlesjones/Embedded-for-Everyone/wiki/1.-Getting-to-%22Blinky%22-with-a-new-MCU">embedded for everyone wiki</a>, there’s an embedded toolchain you have to build up in order to actually program and debug an embedded system. It consists of:</p>
<ol>
<li>a code editor - something on your computer to edit your code</li>
<li>an SDK (software development kit). AKA a library/framework that abstracts some aspects of developing for the given MCU to make it easier to program</li>
<li>Compiler/linker - Converts the application code into a binary which can be executed by the target MCU</li>
<li>Adapter driver - a driver on your computer that talks to the debug adapter</li>
<li>debug adapter - a physical piece of hardware, converts programming and debugging signals from your computer to the format understandable by the MCU</li>
<li>debug software - runs on your computer and connects through the adapter driver and debug adapter to the debugging features on the MCU</li>
</ol>
<p>The Arduino IDE implements the first couple items. It’s a code editor, has a built in SDK, and compiles/links the code. From my understanding, the “debug adapter” is somewhat similar to the AVR programmer I’m using, in that it’s a physical piece of hardware that communicates between the USB port of my computer, and the individual pins of the ATmega328p. I did some research, and it looks like AVR microcontrollers (which the ATmega328 is a member of) have a proprietary protocol called debugWIRE that allows on-chip debugging <a href="https://en.wikipedia.org/wiki/DebugWIRE">https://en.wikipedia.org/wiki/DebugWIRE</a>. You can only use this protocol by buying extra pieces of hardware, some of which can be pretty spendy (Atmel-ICE is 160 at the time of this writing). Since this project is mainly a first-step-into-microcontrollers, and I plan on expanding into STM32 and other microcontrollers, I think I’ll skip on the debug portion of this toolchain.</p>
<p>Arduino doesn’t support on-chip debugging, so they just skip that part of the toolchain. And Arduino doesn’t need a separate programmer like when I program the ATmega328p directly, because ATmega328p microcontrollers that are on Arduino Unos come pre-programmed with a bootloader. The bootloader is a bit of code that lets you plug the Uno directly into the computer, and load custom code on the ATmega328p without extra hardware.</p>
<h2 id="the-ide">The IDE</h2>
<p>This one is simple. I’ve been using Visual Studio Code for a while, and am comfortable moving around in it. It has a built-in terminal too, so I’m sure I can figure out how to use all the other tools in here. And since I’m skipping debugging on-chip, I don’t have to worry about any custom debug software that I would need to incorporate into whatever IDE I choose.</p>
<h2 id="writing-code-for-the-atmega328p">Writing code for the ATmega328p</h2>
<p>Without the Arduino IDE, I no longer have access to the Arduino SDK. So when I copy the standard <code class="language-plaintext highlighter-rouge">blink.ino</code> file into Visual Studio Code, I get a ton of errors. It doesn’t know what <code class="language-plaintext highlighter-rouge">digitalwrite()</code> or any other function is, it doesn’t have a <code class="language-plaintext highlighter-rouge">main()</code> function, it’s just a mess. The reason it worked in the Arduino IDE is because the IDE isn’t JUST a text editor. It has a bunch of C libraries that hide a lot of the complexity of programming an MCU. In my case, I don’t <em>want</em> to hide the complexity though, so it’s gonna get more complicated. Happily, Mitch Davis’ playlist walks you through how to write C code without using the Arduino SDK. Below is my final result, with comments explaining it.</p>
<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="c1">//This is a pointer to the location in memory at hex number 0x25</span>
<span class="c1">//it is a 1-byte register defined by ATmega328p that controls the physical pins 14 thru 19 (mapping to bits 0-5)</span>
<span class="c1">//setting a bit to 0 means it's set to low, setting a bit to 1 means it's high</span>
<span class="c1">//setting it to volatile to alert the compiler this variable can change outside </span>
<span class="c1">//my code, so it doesn't optimize out this value</span>
<span class="cp">#define PORTB *((volatile unsigned char *)0x25)
</span>
<span class="c1">//this is a pointer to the location in memory at hex 0x24</span>
<span class="c1">//this is the Data-direction register for PortB. It controls physical pins 14 thru 19 (mapping to bits 0-5)</span>
<span class="c1">//setting a bit to 0 means the pin is set to input mode, setting to 1 means it's output</span>
<span class="c1">//setting it to volatile to alert the compiler this variable can change outside </span>
<span class="c1">//my code, so it doesn't optimize out this value</span>
<span class="cp">#define DDRB *((volatile unsigned char *)0x24)
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">//setup</span>
<span class="c1">//by setting the 6th bit on this register to 1</span>
<span class="c1">//It is setting the bit that controls physical pin 13, and saying it is an output pin</span>
<span class="c1">//using bitwise OR to turn on the 6th bit without affecting the other bits in DDRB</span>
<span class="n">DDRB</span> <span class="o">|=</span> <span class="mi">0</span><span class="n">b00100000</span><span class="p">;</span>
<span class="c1">// loop</span>
<span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">//by setting the 6th bit on this register to 1</span>
<span class="c1">//It is setting the bit that controls physical pin 13, and setting it to high</span>
<span class="c1">//using bitwise OR to turn on the 6th bit without affecting the other bits in PORTB</span>
<span class="n">PORTB</span> <span class="o">|=</span> <span class="mi">0</span><span class="n">b00100000</span><span class="p">;</span>
<span class="c1">//go to sleep for an arbitrary amount of time</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">long</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="mi">100000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">//to make sure the compiler doesn't optimize this out, continue</span>
<span class="c1">//setting the 6th bit of portb to 1</span>
<span class="n">PORTB</span> <span class="o">|=</span> <span class="mi">0</span><span class="n">b00100000</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//setting PortB 6th bit to 0 sets pins PortB controls to low</span>
<span class="n">PORTB</span> <span class="o">&=</span> <span class="mi">0</span><span class="n">b11011111</span><span class="p">;</span>
<span class="c1">//go to sleep for an arbitrary amount of time</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">long</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="mi">100000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">//to make sure the compiler doesn't optimize this out, continue</span>
<span class="c1">//setting PORTB 6th bit to 0</span>
<span class="n">PORTB</span> <span class="o">&=</span> <span class="mi">0</span><span class="n">b11011111</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="avr-gcc">AVR gcc</h2>
<p>Now that I have code that <em>should</em> run on my ATmega328p, I need to compile it! I can do this with the <code class="language-plaintext highlighter-rouge">avr-gcc</code> program. This lets me compile using a special version of <code class="language-plaintext highlighter-rouge">gcc</code> that compiles to an AVR microcontroller, instead of my x86-64 laptop.</p>
<p>To install, I first tried</p>
<p><code class="language-plaintext highlighter-rouge">sudo apt-get install gcc-avr</code></p>
<p>It gave the below suggested packages, but I’m trying to stay minimal, so lets see how far I can get without installing them.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Suggested packages:
task-c-devel gcc-doc avr-libc
</code></pre></div></div>
<blockquote>
<p><strong>Note from Future Danielle:</strong> I don’t get that far without the <code class="language-plaintext highlighter-rouge">avr-libc</code> package, I recommend installing it too</p>
</blockquote>
<p>After I installed, I couldn’t find any man pages. I tried both <code class="language-plaintext highlighter-rouge">man gcc-avr</code> and <code class="language-plaintext highlighter-rouge">man avr-gcc</code>. When I tried running avr-gcc, I got a <code class="language-plaintext highlighter-rouge">fatal error, no input files</code>. So it did install the avr-gcc package, just no docs. Maybe need to install gcc-doc then? I ran <code class="language-plaintext highlighter-rouge">sudo apt-get install gcc-doc</code>, and it installed these packages:
<code class="language-plaintext highlighter-rouge">gcc-7-doc gcc-doc</code>.</p>
<p>But it still doesn’t work when I do <code class="language-plaintext highlighter-rouge">man avr-gcc</code>. When I watched Mitch’s video though, it shows the man page that shows up is actually the GCC man page. I can go there (<code class="language-plaintext highlighter-rouge">man gcc</code>) and when I scrolled down, I can see AVR options listed there.<br />
<img src="/assets/programming-an-atmega328-without-the-arduino-ide/gcc man page.png" alt="Gcc's man page that shows AVR options" /></p>
<blockquote>
<p><strong>NOTE</strong> I noticed it also has an option for MIPS, which I remember from my router research. So I wonder if I can write programs for my router and make it run my custom code?</p>
</blockquote>
<p>The main <code class="language-plaintext highlighter-rouge">man</code> page doesn’t seem to have a lot of in-depth info about the avr side of things. It does mention a <code class="language-plaintext highlighter-rouge">--help</code> flag. Maybe that’ll trigger more AVR-specific help?
Running <code class="language-plaintext highlighter-rouge">avr-gcc --help</code> gives a small list of flags. But one of them is <code class="language-plaintext highlighter-rouge">--target-help</code>, which says it will <code class="language-plaintext highlighter-rouge">Display target specific command line options</code>. Well that sounds helpful! Running that command gives me a ton of info, so I put it into the <code class="language-plaintext highlighter-rouge">less</code> command to make it easier to scroll through.</p>
<p><code class="language-plaintext highlighter-rouge">avr-gcc --target-help | less</code></p>
<p><img src="/assets/programming-an-atmega328-without-the-arduino-ide/list of accepted AVR MCUs.png" alt="the target-help screen, which displays a list of currently known MCU names. A huge list of MCUs, with the ATmega328p highlighted" />
Ah! I can see that ATmega328 is a supported option for <code class="language-plaintext highlighter-rouge">avr-gcc</code>, that’s good!</p>
<p>Now that <code class="language-plaintext highlighter-rouge">avr-gcc</code> is installed, let’s compile! I tried to compile just the blink.c file, and…</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>avr-gcc -mmcu=atmega328p blink.c
/usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: cannot find crtatmega328p.o: No such file or directory
/usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: cannot find -lm
/usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: cannot find -lc
/usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: cannot find -latmega328p
collect2: error: ld returned 1 exit status
</code></pre></div></div>
<p>Errors! What’s this <code class="language-plaintext highlighter-rouge">ld</code> program? I do a <code class="language-plaintext highlighter-rouge">man ld</code> and see it’s the GNU linker. Well I don’t think I need that linker, cuz all my code is in one file and I’m not using any libraries. Lets see if I can turn that off…</p>
<blockquote>
<p><strong>NOTE</strong> a linker collects compiled files that should all be combined into a single program together. So it grabs precompiled libraries and adds them to your code if you call them at some point, stuff like that.</p>
</blockquote>
<p>Looking at that <code class="language-plaintext highlighter-rouge">--target-help</code> more, I see this flag:</p>
<p><code class="language-plaintext highlighter-rouge">-nodevicelib Do not link against the device-specific library lib<MCU>.a</code></p>
<p>that seems useful, but after trying it, I get the same error. Maybe I should check the general <code class="language-plaintext highlighter-rouge">gcc</code> man page, and hunt for linker info there. The <code class="language-plaintext highlighter-rouge">man gcc | grep linker</code> command gives me a hint that maybe <code class="language-plaintext highlighter-rouge">-c</code> could be of help? Reading the flag info:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Compile or assemble the source files, but do not link. The linking stage simply is
not done. The ultimate output is in the form of an object file for each source file.
</code></pre></div></div>
<p>That sounds like what I want to do, so let’s try:</p>
<p><code class="language-plaintext highlighter-rouge">avr-gcc -mmcu=atmega328p -c blink.c</code></p>
<p>Using that, it compiles into <code class="language-plaintext highlighter-rouge">blink.o</code>. Progress! Opening up that file with bless hex editor, I can see that the file starts with <code class="language-plaintext highlighter-rouge">.ELF</code>, which stands for “Executable and Linkable Format”. I can confirm that it’s an ELF file type by using the <code class="language-plaintext highlighter-rouge">file</code> command</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> file blink.o
blink.o: ELF 32-bit LSB relocatable, Atmel AVR 8-bit, version 1 (SYSV), not stripped
</code></pre></div></div>
<p>So now that it’s compiled, I need to send it to the ATmega328p. I can do this using the same tool I used last time to set the fuse bits, avrdude!</p>
<h2 id="avrdude">AVRdude</h2>
<p>Since I don’t want to use the arduino IDE version of avrdude, I need to install avrdude myself.</p>
<p>To install, did:</p>
<p><code class="language-plaintext highlighter-rouge">sudo apt install avrdude avrdude-doc</code></p>
<p>(I’m not making the same mistake as last time, and grabbing the docs at the same time)
Once that’s complete, I now need to try to send over the <code class="language-plaintext highlighter-rouge">blink.o</code> ELF file. I can use my knowledge gained from last time to take a first stab at the command. I know to set what programmer I’m using, what chip I’m targeting, can set verbose logging, and need to set the port and baudrate. The difference is the <code class="language-plaintext highlighter-rouge">-U</code> setting. I don’t want to set the low fuse bit, I want to set the flash memory on the chip. And I want to write my <code class="language-plaintext highlighter-rouge">blink.o</code> file to it, and tell avrdude I’m using an ELF file. Reading through the <a href="https://www.nongnu.org/avrdude/user-manual/avrdude_4.html#Option-Descriptions">online documentation</a> I figure out what I should do. The (tentative) command to run should be:</p>
<p><code class="language-plaintext highlighter-rouge">avrdude -v -p atmega328p -c stk500v1 -P /dev/ttyUSB0 -b 19200 -U flash:w:blink.o:e</code></p>
<p>I try that and… aw, errors galore!</p>
<p>Specifically, AVRdude is saying the ELF file isn’t an executable. And in fact, you can see that in the <code class="language-plaintext highlighter-rouge">file</code> command I ran. It’s not a LSB executable, it’s a relocatable. Removing the linker step with the <code class="language-plaintext highlighter-rouge">-c</code> flag means I’m not making an executable. Dang!</p>
<p>Looking at the error from when I tried to compile without the <code class="language-plaintext highlighter-rouge">-c</code> flag earlier, it’s complaining about a missing file <code class="language-plaintext highlighter-rouge">crtatmega328p.o</code>. That sounds like a compiled c file that’s called “crtatmega328p”. Which matches what chip I’m targeting. And it’s the linker that’s having issues. So my theory: <code class="language-plaintext highlighter-rouge">avr-gcc</code> default pulls in compiled c files for the given target MCU. Those files aren’t downloaded as part of the <code class="language-plaintext highlighter-rouge">avr-gcc</code> package. Looking back at the suggested packages way back when I first installed <code class="language-plaintext highlighter-rouge">avr-gcc</code>, I see a package that’s called <code class="language-plaintext highlighter-rouge">avr-libc</code>. That sounds like a package with a bunch of c libraries in it to me. I can run <code class="language-plaintext highlighter-rouge">sudo apt show avr-libc</code> to see more info on the libc package, and see the below description:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Description: Standard C library for Atmel AVR development
Standard library used to the development of C programs for the
Atmel AVR micro controllers. This package contains static
libraries as well as the header files needed.
</code></pre></div></div>
<p>Yup, that sounds like what I need. I install that, and then try to run my initial <code class="language-plaintext highlighter-rouge">avr-gcc</code> command again, without the <code class="language-plaintext highlighter-rouge">-c</code> flag, and it builds. I ran a <code class="language-plaintext highlighter-rouge">file</code> command on the output, and it’s now an executable! I try again with my <code class="language-plaintext highlighter-rouge">avrdude</code> command earlier, and it works! I’m now flashing an LED on and off with my ATmega328p and no Arduino IDE!</p>
<p>So, with gcc-avr, avr-libc, and avrdude packages installed, I can upload code with only two commands:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>avr-gcc -mmcu=atmega328p blink.c
avrdude -v -c /etc/avrdude.conf -p atmega328p -c stk500v1 -P /dev/ttyUSB0 -b 19200 -U flash:w:a.out:e
</code></pre></div></div>
<h3 id="the-other-way">The other way</h3>
<p>Now all this was me kind of going at it from first principles. I wanted to figure out how to get this working with the minimal of mysterious command line invocations. HOWEVER, this isn’t the way that people on the internet want you to do it. They all say after you compile your code, you need to convert it into an intel hex file, then send <em>that</em> to the MCU using avrdude. I haven’t seen why you convert it to hex, beyond that’s what people do. There’s also a line from Mitch Davis saying he didn’t know how to get the compiled file from <code class="language-plaintext highlighter-rouge">avr-gcc</code> over to the MCU, so I’m wondering if the <code class="language-plaintext highlighter-rouge">e</code> format for AVRdude is a new feature?</p>
<p>Anyway, to convert the ELF executable to hex, you can use the <code class="language-plaintext highlighter-rouge">avr-objcopy</code> command, which I think comes over with the <code class="language-plaintext highlighter-rouge">avr-gcc</code> package. As part of the conversion, you can also tell it to only copy the relevent parts of the executable, namely, the text and data sections. This does have the nice affect of shrinking the file down. The initial version of the <code class="language-plaintext highlighter-rouge">a.out</code> file is 6520 according to the <code class="language-plaintext highlighter-rouge">ls -l</code> command, and the output after <code class="language-plaintext highlighter-rouge">avr-objcopy</code> is only 860! So that’s certainly a nice feature of using <code class="language-plaintext highlighter-rouge">avr-objcopy</code>. But if you’re just doing a blink project like me, I suspect size doesn’t really matter.</p>
<p>if you want to make a hex file and send it over:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>avr-gcc -mmcu=atmega328p blink.c
avr-objcopy -O ihex -j.text -j.data a.out a-small.hex
avrdude -v -c /etc/avrdude.conf -p atmega328p -c stk500v1 -P /dev/ttyUSB0 -b 19200 -U flash:w:a-small.hex:i
</code></pre></div></div>
<h2 id="playing-with-size">Playing with Size</h2>
<p>Now that I have a working set up, I want to tinker a bit. For embedded systems, minimizing the size of your code can be important, since they’re so much more restrained, memory-wise, than other systems you’re used to programming. Right now I’ve been running <code class="language-plaintext highlighter-rouge">avr-gcc</code> without any more than the bare-minimum, but I can make the compiler compile things smaller or faster, with the use of optimization flags! Poking through the <code class="language-plaintext highlighter-rouge">gcc</code> man file, I found the <code class="language-plaintext highlighter-rouge">-Os</code> flag optimizes for size, which is what I’m after right now. The man page says:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-Os Optimize for size. -Os enables all -O2 optimizations that do not
typically increase code size.
-Os disables the following optimization flags: -falign-functions
-falign-jumps -falign-loops -falign-labels -fprefetch-loop-arrays
It also enables -finline-functions, causes the compiler to tune for
code size rather than execution speed, and performs further
optimizations designed to reduce code size.
</code></pre></div></div>
<p>And as I mentioned earlier, the official process for uploading code using avrdude includes using an <code class="language-plaintext highlighter-rouge">avr-objcopy</code> command to convert it to hex. My working theory is that has something to do with code size, so let’s do some scientific inquiry to see if that’s the case. I’ll try a bunch of different compilation, grabbing only .text and .data sections, and converting to hex, and see if one version is smaller than another. My plan is to take my <code class="language-plaintext highlighter-rouge">blink.c</code> file, and do the following.</p>
<ol>
<li>compile without optimizations</li>
<li>compile with optimizations</li>
<li>For each version (with and without optimizations)
<ol>
<li>grab only .text and .data pieces</li>
<li>convert to hex</li>
<li>take the ELF that has only the .text and .data pieces, convert to hex</li>
</ol>
</li>
</ol>
<p>So the commands for this were as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>avr-gcc -mmcu=atmega328p -o a.out blink.c
avr-gcc -Os -mmcu=atmega328p -o a-small.out blink.c
#deal with a-small.out
avr-objcopy -O ihex a-small.out a-small.hex
avr-objcopy -j.text -j.data a-small.out a-small-trimmed.out
avr-objcopy -O ihex a-small-trimmed.out a-small-trimmed.hex
#deal with a.out
avr-objcopy -O ihex a.out a.hex
avr-objcopy -j.text -j.data a.out a-trimmed.out
avr-objcopy -O ihex a-trimmed.out a-trimmed.hex
</code></pre></div></div>
<p>And the size results:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-rw-rw-r-- 1 danielle danielle 987 Jun 4 13:13 a.hex
-rwxrwxr-x 1 danielle danielle 6564 Jun 4 13:12 a.out
-rw-rw-r-- 1 danielle danielle 508 Jun 4 13:12 a-small.hex
-rwxrwxr-x 1 danielle danielle 6396 Jun 4 13:12 a-small.out
-rw-rw-r-- 1 danielle danielle 508 Jun 4 13:12 a-small-trimmed.hex
-rwxrwxr-x 1 danielle danielle 1792 Jun 4 13:12 a-small-trimmed.out
-rw-rw-r-- 1 danielle danielle 987 Jun 4 13:13 a-trimmed.hex
-rwxrwxr-x 1 danielle danielle 1960 Jun 4 13:13 a-trimmed.out
</code></pre></div></div>
<p>Some conclusions we can draw for this particular program:</p>
<ol>
<li>if it’s converted to hex, it doesn’t matter if we grab only the .text and .data pieces, or if we take the whole thing to convert to hex, it comes out the same size. So either the conversion to hex only uses the .text and .data pieces, or my program doesn’t use anything besides the .text and .data bits, so it doesn’t matter.</li>
<li>Running the optimization at the compiler level helps both at the initital compilation, and when converting to hex. Which would be frankly weird if this wasn’t the case, but now I have some proof.</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>This was super fun! I got to build out an embedded system toolchain (minus on-chip debugging functionality), and read a lot of <code class="language-plaintext highlighter-rouge">man</code> pages in the process. Using the Arduino Uno as an initial jumping-off point for microcontrollers feels really helpful, and let me get into toolchains and programmers and debuggers in a real step-by-step process.</p>
<p>Now that I’ve got my feet wet, it’s time to expand my knowledge pool! I had a quick shopping spree at Adafruit (they’re so easy to have a shopping spree at…), and now have some goodies to help me learn about Bluetooth Low Energy, STM32, ESP32, and Real Time Operating Systems.</p>
<h2 id="resources">Resources</h2>
<p>Embedded for everyone github repo: <a href="https://github.com/nathancharlesjones/Embedded-for-Everyone/wiki/1.-Getting-to-%22Blinky%22-with-a-new-MCU">https://github.com/nathancharlesjones/Embedded-for-Everyone/wiki/1.-Getting-to-%22Blinky%22-with-a-new-MCU</a></p>
<p>Bare-metal MCU playlist: <a href="https://www.youtube.com/watch?v=7lcY5tcP_ow&list=PLNyfXcjhOAwOF-7S-ZoW2wuQ6Y-4hfjMR&index=6">https://www.youtube.com/watch?v=7lcY5tcP_ow&list=PLNyfXcjhOAwOF-7S-ZoW2wuQ6Y-4hfjMR&index=6</a></p>
<p>AVRdude Documentation: <a href="https://www.nongnu.org/avrdude/user-manual/avrdude_4.html#Option-Descriptions">https://www.nongnu.org/avrdude/user-manual/avrdude_4.html#Option-Descriptions</a></p>Now that I have an AVR programmer and the ATmega328p on its own breadboard (as I documented here), I want to remove my dependence on the Arduino IDE download. So no more using tools that arduino IDE downloaded for me! My rough plan is as follows: pick a different IDE for writing my code either write C code without any AVR-specific libraries, or find a SDK download avr-gcc so I can compile my code download AVRdude so I can send my compiled code to the ATmega328p figure out if there’s any other things I have to download or run?Directly Programming an ATmega328p from an Arduino Uno2021-05-25T00:00:00+00:002021-05-25T00:00:00+00:00/blog/2021/5/25/directly-programming-an-atmega328p-from-an-arduino-uno<p>So Arduino’s brains is a ATmega328p microcontroller. On the standard Arduino Uno, it comes as a chip that you can remove from the board, so if you fry it on accident, you can replace just the chip instead of the whole board. So is it possible to remove all the stuff Arduino gives you, take just the chip, and directly program the ATmega328p?</p>
<p>Well I came across a youtube playlist recently that gives a resounding yes, yes you can. Mitch Davis’ <a href="https://www.youtube.com/playlist?list=PLNyfXcjhOAwOF-7S-ZoW2wuQ6Y-4hfjMR">Bare-Metal MCU playlist</a> walks you through taking all the helpful things Arduino gives you, and removing them one by one. This sort of content is <em>exactly</em> up my alley, and I realized I had an Uno kicking around, plus a sparkfun version of an Uno, a <a href="https://www.sparkfun.com/products/13975">sparkfun redboard</a>. Why not follow along?
<!--more-->
So, using Mitch Davis’ playlist as a basis, I decided to do the following:</p>
<ul>
<li>Take my existing Redboard, make it into an ISP (In-circuit Serial Programmer).</li>
<li>Change the Fuse setting so the ATmega328p chip uses the internal clock instead of external</li>
<li>Remove the ATmega328p chip from my arduino uno, put it on a breadboard</li>
<li>validate the ATmega328p can run my blink program while sitting on the breadboard, getting no help from the Arduino PCB</li>
<li>connect it to the ISP and flash a new program on it</li>
<li>???</li>
<li>cackle at my brilliance</li>
</ul>
<blockquote>
<p><strong>NOTE:</strong> that last step is non-optional when I’m playing with tech</p>
</blockquote>
<p><br /></p>
<hr />
<p><strong><em>This is a part of my series on programming atmega328p</em></strong></p>
<p>For more posts on this, see below</p>
<ol>
<li>
<a href="/blog/2021/5/25/directly-programming-an-atmega328p-from-an-arduino-uno">Directly Programming an ATmega328p from an Arduino Uno</a>
(You are Here)
</li>
<li>
<a href="/blog/2021/6/8/programming-an-atmega328p-without-the-arduino-ide">Programming an ATmega328p without the Arduino IDE</a>
</li>
</ol>
<hr />
<p><br /></p>
<h2 id="making-the-redboard-into-an-isp">Making the redboard into an ISP</h2>
<p>This was shockingly easy! The Arduino IDE comes with Arduino ISP code in the Examples section by default. So all I had to do was connect my redboard to my computer, then send the ISP code from the Arduino IDE to my redboard just like normal, and voila, I now have a ISP. Neat!</p>
<blockquote>
<p><strong>NOTE</strong>: going forward, I’ll refer to the Arduino Uno-compatible redboard as “the ISP” to reduce confusion on if I’m talking about the Arduino Uno I want to reprogram, or the arduino Uno-compatible sparkfun redboard I’m using as the ISP.</p>
</blockquote>
<h2 id="connecting-the-isp-to-the-arduino-uno-and-sending-code">Connecting the ISP to the arduino Uno and Sending Code</h2>
<p>Following Mitch’s tutorial, I have the following pin connections, from the ISP to Uno:</p>
<ul>
<li>13 to 13</li>
<li>12 to 12</li>
<li>11 to 11</li>
<li>10 to reset</li>
<li>5v to 5v</li>
<li>Gnd to Gnd</li>
</ul>
<p>It’s all one-to-one except for pin 10 on the ISP to the reset pin on the Uno. This is because the ISP needs to muck with the reset pin in order to program the Uno. The Arduino ISP example code default uses pin 10 for that communication.</p>
<p><img src="/assets/directly-programming-an-atmega328p-from-an-arduino-uno/20210525_111243.jpg" alt="The newly made ISP redboard, connected directly to the Arduino Uno" />
The ISP connected to the Arduino Uno</p>
<p>Reading Arduino’s documentation about the arduino ISP code and the comments in the ISP code, it says it uses 3 pins on the arduino you’re using as an ISP to give more info about the ISP. Connecting up pins 7, 8, and 9 on an Arduino Uno ISP (or redboard, in my case) to some LEDs and resistors let you see the heartbeat, error, and programming info. The comment in the code sums it up nicely:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Put an LED (with resistor) on the following pins:
// 9: Heartbeat - shows the programmer is running
// 8: Error - Lights up if something goes wrong (use red if that makes sense)
// 7: Programming - In communication with the slave
</code></pre></div></div>
<p>Though the “slave” terminology seems to be a hold over from older code, since elsewhere it’s referred to as “target”. I hunted down the right github repo and did a pull request to update that line of code. So if that gets merged in, I’ll have technically contributed to the Arduino IDE example code base. Since it’s a comment it doesn’t change the runnable code one iota, but still.</p>
<p>Now I update the Arduino IDE to use “Arduino as ISP” as the Programmer (the setting is under the “tools” dropdown), and I can send the example <code class="language-plaintext highlighter-rouge">blink.ino</code> program to the Uno, using my brand new ISP! If I want to see more info about what the Arduino IDE is actually doing when it sends the code over, I can go to File -> Preferences, and set the “show verbose output during” checkboxes for both compilation and uploading. I then open the <code class="language-plaintext highlighter-rouge">blink.ino</code> sketch in the IDE, and upload it using <code class="language-plaintext highlighter-rouge">Sketch->Upload using Programmer</code>.</p>
<p>After sending the blink code to the uno, the on-board LED is flashing on my ISP <em>and</em> my uno. It took me a bit to figure that out. The blink program is makng LED_BUILTIN high and low to flash the built in LED on and off. Well LED_BUILTIN is just a constant that is referencing the pin on the arduino that is connected to the onboard LED. On the Uno, that’s pin 13. So after the ISP uses pin 13 to send data to the Uno, now the Uno is powering pin 13 on and off, and the wire is still connected to pin 13 on the ISP, so the ISP blinks too.</p>
<p>Looking in the logs the IDE prints out, I can find the command that arduino IDE used to flash the blink program onto the uno via the ISP.</p>
<p><code class="language-plaintext highlighter-rouge">/home/danielle/arduino-1.8.13-linux64/arduino-1.8.13/hardware/tools/avr/bin/avrdude -C/home/danielle/arduino-1.8.13-linux64/arduino-1.8.13/hardware/tools/avr/etc/avrdude.conf -v -patmega328p -cstk500v1 -P/dev/ttyUSB0 -b19200 -Uflash:w:/tmp/arduino_build_984737/Blink.ino.hex:i</code></p>
<p>This is an important thing to note. AVRDude is a utility to download/upload/manipulate the ROM and EEPROM contents of AVR microcontrollers using the in-system programming technique (ISP). (this is taken straight from <a href="https://www.nongnu.org/avrdude/">their website</a>) The ATmega328 is an AVR microcontroller, and I just made an ISP. Since it’s a command line tool, I can actually use the tool directly, without using the Arduino IDE. This is important for the fuse bytes that I’ll talk about shortly.</p>
<p>Now that I’ve figured out how to make an ISP, and proving it works, the next step I want to do is rip the ATmega328 off of the Uno so I can play with it directly. But first, I have to change a setting on the chip that Arduino sets at the factory.</p>
<h2 id="fuse-bits">Fuse Bits</h2>
<p>There’s actually an in-depth blog post that talks about fuse bits in detail: <a href="https://embedderslife.wordpress.com/2012/08/20/fuse-bits-arent-that-scary/">https://embedderslife.wordpress.com/2012/08/20/fuse-bits-arent-that-scary/</a>. But basically, they’re a series of bits that configure different settings on the microcontroller itself. Like a config file on a website that says what port it uses and routing info.</p>
<p>I care about this because of what Arduino does to the fuse bits in their factory. ATmega328 has a 8Hz oscillator on the chip that it uses as a clock, but it CAN run up to 16Hz (according to the datasheet). So Arduino adds a 16Hz oscillator on the Uno PCB and connects it to the ATMega328. This lets it run faster than when using the default 8Hz. But it also means, if the ATMega328 doesn’t have an oscillator hooked up, it just straight up can’t run, because it doesn’t know how to time anything!</p>
<p>So before removing the ATmega328 from the Uno, I have to update the fuse bits to go back to using the on-chip 8Hz clock. How? Why by using avrdude!</p>
<p>To read the low fuse byte, look at the arduino IDE verbose setting to see where the avrdude downloaded by arduino lives, and go there. Mine was in a <code class="language-plaintext highlighter-rouge">/home/danielle/arduino-1.8.13-linux64/arduino-1.8.13/hardware/tools/avr</code> folder. Then, I ran the following command</p>
<p><code class="language-plaintext highlighter-rouge">./bin/avrdude -C ./etc/avrdude.conf -v -p atmega328p -c stk500v1 -P /dev/ttyUSB0 -b 19200 -U lfuse:r:/tmp/lfusesetting:h</code></p>
<blockquote>
<p><strong>NOTE</strong> the baudrate setting to 19200 (using the <code class="language-plaintext highlighter-rouge">-b 19200</code> flag), was required to get avrdude working. Otherwise I get a “Yikes! Invalid device signature.” error.</p>
</blockquote>
<p>If you want to go in-depth on what all this means, you can read the avrdude docs here: <a href="https://www.nongnu.org/avrdude/user-manual/avrdude_4.html#Option-Descriptions">https://www.nongnu.org/avrdude/user-manual/avrdude_4.html#Option-Descriptions</a>. But basically I’m telling it:</p>
<ol>
<li>what chip I’m using (<code class="language-plaintext highlighter-rouge">atmega328p</code>)</li>
<li>what ISP I’m using (though I lie and say <code class="language-plaintext highlighter-rouge">stk500v1</code> instead of the arduino as ISP, because that’s what the IDE did)</li>
<li>where the ISP is on my computer (<code class="language-plaintext highlighter-rouge">/dev/ttyUSB0</code>)</li>
<li>baud rate (<code class="language-plaintext highlighter-rouge">19200</code>)</li>
<li>and what to do: for the low fuse byte (<code class="language-plaintext highlighter-rouge">lfuse</code>), read (<code class="language-plaintext highlighter-rouge">r</code>) it, and write the value to <code class="language-plaintext highlighter-rouge">/tmp/lfusesetting</code>, as a hex (<code class="language-plaintext highlighter-rouge">h</code>) value</li>
</ol>
<p>After I run that command, I use <code class="language-plaintext highlighter-rouge">cat</code> on <code class="language-plaintext highlighter-rouge">/tmp/lfusesetting</code> to get: <code class="language-plaintext highlighter-rouge">0xff</code>, which is what Mitch Davis says the low fuse is default set to by Arduino.</p>
<p>To update it, I change just the clock select bits to <code class="language-plaintext highlighter-rouge">0010</code> so it uses the internal 8Hz oscillator. This would change the low fuse byte to <code class="language-plaintext highlighter-rouge">0xf2</code>. So the command to update the low fuse is:</p>
<p><code class="language-plaintext highlighter-rouge">./bin/avrdude -C ./etc/avrdude.conf -v -p atmega328p -c stk500v1 -P /dev/ttyUSB0 -b 19200 -U lfuse:w:0xF2:m</code></p>
<p>Which outputs below:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>avrdude: Version 6.3-20190619
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
Copyright (c) 2007-2014 Joerg Wunsch
System wide configuration file is "./etc/avrdude.conf"
User configuration file is "/home/danielle/.avrduderc"
User configuration file does not exist or is not a regular file, skipping
Using Port : /dev/ttyUSB0
Using Programmer : stk500v1
Overriding Baud Rate : 19200
AVR Part : ATmega328P
Chip Erase delay : 9000 us
PAGEL : PD7
BS2 : PC2
RESET disposition : dedicated
RETRY pulse : SCK
serial program mode : yes
parallel program mode : yes
Timeout : 200
StabDelay : 100
CmdexeDelay : 25
SyncLoops : 32
ByteDelay : 0
PollIndex : 3
PollValue : 0x53
Memory Detail :
Block Poll Page Polled
Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack
----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
eeprom 65 20 4 0 no 1024 4 0 3600 3600 0xff 0xff
flash 65 6 128 0 yes 32768 128 256 4500 4500 0xff 0xff
lfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
hfuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
efuse 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
lock 0 0 0 0 no 1 0 0 4500 4500 0x00 0x00
calibration 0 0 0 0 no 1 0 0 0 0 0x00 0x00
signature 0 0 0 0 no 3 0 0 0 0 0x00 0x00
Programmer Type : STK500
Description : Atmel STK500 Version 1.x firmware
Hardware Version: 2
Firmware Version: 1.18
Topcard : Unknown
Vtarget : 0.0 V
Varef : 0.0 V
Oscillator : Off
SCK period : 0.1 us
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.04s
avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DE
avrdude: safemode: efuse reads as FD
avrdude: reading input file "0xF2"
avrdude: writing lfuse (1 bytes):
Writing | ################################################## | 100% 0.05s
avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xF2:
avrdude: load data lfuse data from input file 0xF2:
avrdude: input file 0xF2 contains 1 bytes
avrdude: reading on-chip lfuse data:
Reading | ################################################## | 100% 0.02s
avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: safemode: lfuse reads as F2
avrdude: safemode: hfuse reads as DE
avrdude: safemode: efuse reads as FD
avrdude: safemode: Fuses OK (E:FD, H:DE, L:F2)
avrdude done. Thank you.
</code></pre></div></div>
<p>It’s cool it shows all fuse settings right now too, so I can compare with the data sheet to see what the fuse bits are currently set as.</p>
<blockquote>
<p><strong>NOTE:</strong> Figuring out what changes to the Fuse bits you should do is pretty confusing. And if you accidentally set the wrong bit, you could potentially brick the ATmega328p! There are fuse bit calculators out there that try to improve the process some though. The one Mitch uses is this one: <a href="http://eleccelerator.com/fusecalc/fusecalc.php?chip=atmega328p">http://eleccelerator.com/fusecalc/fusecalc.php?chip=atmega328p</a></p>
</blockquote>
<h3 id="side-track-the-high-fuse-byte">Side track, the high fuse byte</h3>
<p>Just for fun, let’s take a look at the current setting of the high fuse byte. Hfuse is <code class="language-plaintext highlighter-rouge">0xDE</code>, which in binary is <code class="language-plaintext highlighter-rouge">1101 1110</code>. Let’s go through it a nibble at a time (4 bits at a time).</p>
<p>The first four bits, <code class="language-plaintext highlighter-rouge">1101</code>, are a series of individual settings. Going left to right, the first bit is if the reset pin works. This is needed for programming with the ISP. The documentation is kind of confusing on this one. Setting it to <code class="language-plaintext highlighter-rouge">0</code> means “on”, but the setting is “disable the reset pin”. So really, it’s <code class="language-plaintext highlighter-rouge">1</code> if the reset pin is enabled, <code class="language-plaintext highlighter-rouge">0</code> if not. The next bit turns off the debug wire setting (I don’t know what that means, but I’m not touching it). Next bit is enabling serial programming. We definitely want this enabled! And again, it’s kind of weird, because THIS bit’s setting is “enable serial programming”, and since <code class="language-plaintext highlighter-rouge">0</code> means “on”, we want to set this to <code class="language-plaintext highlighter-rouge">0</code>. So it’s opposite of the reset pin bit, but the end result is enabling both the reset pin and serial programming. The last bit in this nibble sets if the watchdog timer is always on. It default sets to <code class="language-plaintext highlighter-rouge">1</code>, which means the watchdog timer is not always on.</p>
<p>On to the next nibble! Continuing left to right, the first bit set to <code class="language-plaintext highlighter-rouge">1</code> which means it will not preserve EEPROM memory when the chip is erased.
The last three bits, <code class="language-plaintext highlighter-rouge">110</code>, collectively set boot size. They set the boot flash size as 256 words, and the boot start address is 0x3F00. So this is setting the microcontroller so it knows that there’s a bootloader in flash memory in the range 0x3F00 - 0x3FFF, and on start up, it should start looking for instructions at 0x3F00. Cool!</p>
<p>But enough playing around, now that the low fuse byte is set, the ATmega328p should be able to run by itself, outside of the arduino Uno PCB board. Lets pry it off and see what happens!</p>
<h2 id="running-blink-without-the-uno">Running Blink without the Uno</h2>
<p>First, I have to pry off the ATmega328 without damaging the pins. It was in there tight, and one pin is a little wonky now, but they’re all still attached properly and it fits in the breadboard just fine. With the ATmega328 safely on the breadboard, I have to give it power and add an LED/resistor set up on pin 13, then it should work!</p>
<p><img src="/assets/directly-programming-an-atmega328p-from-an-arduino-uno/20210525_111428.jpg" alt="The Arduino Uno PCB, next to the ATmega328p placed on a breadboard" />
The ATmega328p removed from the Uno and placed on a breadboard. I set it so row 1 on the breadboard is the same as physical pin 1, to help me wire it up correctly.</p>
<p>There’s only one problem, the ATmega328’s physical pin 13 doesn’t match with the digital pin 13 on the arduino Uno. But by using the Arduino pin mapping: <a href="https://www.arduino.cc/en/Hacking/PinMapping168">https://www.arduino.cc/en/Hacking/PinMapping168</a> I can see that pin 13 on the Uno is actually physical pin 19 on the ATmega328. The mapping also shows the Vcc and ground on the ATmega328, so I have everything I need to power up the ATmega328 and see if it runs the blink program!</p>
<blockquote>
<p><strong>NOTE:</strong> When I say “physical pin X”, I’m talking about the pin on the ATmega328 that is labeled as X on the official pinout diagram. You can see it on that Arduino to ATmega328 pin mapping image above, or in the documenation here: <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf">http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf</a>, just do a <code class="language-plaintext highlighter-rouge">ctrl+f</code> for “pinout” to find the right form factor.</p>
</blockquote>
<p><img src="/assets/directly-programming-an-atmega328p-from-an-arduino-uno/20210525_141511.jpg" alt="The ISP is next to the breadboard with the atmega328. the ISP is providing power, but no other connections. The breadboard has multiple wires on it and a single LED" />
The ATmega328p is getting power from the ISP, but nothing else. If I set the fuse bits correctly, it’s using it’s internal oscillator as a clock and running my blink code.</p>
<blockquote>
<p><strong>NOTE:</strong> the LED in this picture doesn’t have a resistor attached to it. That’s because this particular LED actually has a built-in resistor, since it’s from an intro-to-microcontrollers kit, and they didn’t want accidental frying of LEDs, apparently.</p>
</blockquote>
<p>Success! The LED blinks! Notice I also have a wire coming from the physical pin 1 to the positive voltage. This is the reset pin on the ATmega328, and I add that because if the reset pin gets pulled low at some point, it will reset the ATmega328. I don’t want that, so for now, I just connect it with the 5.5v power source and call it good.</p>
<h2 id="flashing-new-programs-on-the-atmega328">Flashing New Programs on the ATmega328</h2>
<p>Using the Uno to ATmega328 mapping that Arduino gives me, I can add wires between the ISP and the ATmega328 so I can put new programs onto it. This way I don’t have to put it back into the Uno PCB every time! The connections, from ISP to ATmega328 are:</p>
<ul>
<li>13 to physical pin 19</li>
<li>12 to physical pin 18</li>
<li>11 to physical pin 17</li>
<li>10 to physical pin 1 (reset)</li>
<li>5v to physical pin 7 (already done, to power the ATmega328)</li>
<li>Gnd to physical pin 8 (already done, to power the ATmega328)</li>
</ul>
<blockquote>
<p><strong>NOTE:</strong> since the ISP pin 13 is connected to the physical pin 19 (which is where the LED is), once again the ISP’s onboard LED will light up in time with the ATmega328.</p>
</blockquote>
<p><img src="/assets/directly-programming-an-atmega328p-from-an-arduino-uno/20210525_125903.jpg" alt="The ATmega328p wired up on the breadboard, with the ISP connected with multiple wires, following the mapping I say above" />
With that set up done, I should be able to flash a new program on the ATmega328 with the Arduino IDE.</p>
<p>And as a fun side bonus, since the LED is physical pin 19, which doubles as the clock pin for the ISP, we’ll see the LED flash while the data is getting put onto the ATmega328. LED flashing = flashing the program. Fun!</p>
<p>I updated the <code class="language-plaintext highlighter-rouge">blink.ino</code> file in a <em>very</em> complicated way, to make sure I could tell when I had successfully flashed a new copy of <code class="language-plaintext highlighter-rouge">blink.ino</code> onto the ATmega328, then sent it using the Arduino IDE “upload using programmer” option. A few seconds of flashing later, I had my results. Success again!</p>
<p>Here’s my “complicated” updated code. I made it blink twice with different waits, so it’s clear this is the new version. The old version I had running was the standard blink program.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(250); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500); // wait for a second
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500); // wait for a second
}
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>I’ve managed to yank the poor ATmega328p from its safe Uno home and showed it a wider world. Next up, I’ll start removing my dependence on the Arduino IDE. Eventually, I’m hoping I’ll understand the whole toolchain needed for programming the ATmega328p, and by extension, AVR microcontrollers in general. Maybe as I learn more about lower level embedded programming, I can think about building custom embedded systems!</p>
<h2 id="resources">Resources</h2>
<p>Mitch Davis’ playlist on breaking down the arduino Uno into bare metal: <a href="https://www.youtube.com/playlist?list=PLNyfXcjhOAwOF-7S-ZoW2wuQ6Y-4hfjMR">https://www.youtube.com/playlist?list=PLNyfXcjhOAwOF-7S-ZoW2wuQ6Y-4hfjMR</a></p>
<p>The ATmega328 datasheet. This is specifically for the ATmega328P, but doesn’t have the pinout for the form factor the arduino Uno uses. Look at the generic ATmega328 datasheet below for that <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf">http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf</a></p>
<p>Generic ATmega328 and a couple of other microcontrollers datasheet. Includes the pinout for the ATmega328 used in the Uno <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf">http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf</a></p>
<p>AVR Fuse Calculator - <a href="http://eleccelerator.com/fusecalc/fusecalc.php?chip=atmega328p">http://eleccelerator.com/fusecalc/fusecalc.php?chip=atmega328p</a></p>
<p>Pin mapping from arduino - <a href="https://www.arduino.cc/en/Hacking/PinMapping168">https://www.arduino.cc/en/Hacking/PinMapping168</a></p>
<p>AVRDude command line option doc: <a href="https://www.nongnu.org/avrdude/user-manual/avrdude_4.html#Option-Descriptions">https://www.nongnu.org/avrdude/user-manual/avrdude_4.html#Option-Descriptions</a></p>
<p>Arduino’s documentation for the Arduino ISP <a href="https://www.arduino.cc/en/pmwiki.php?n=Tutorial/ArduinoISP">https://www.arduino.cc/en/pmwiki.php?n=Tutorial/ArduinoISP</a></p>
<p>Sparkfun’s hookup guide <a href="https://learn.sparkfun.com/tutorials/installing-an-arduino-bootloader#hardware-hookup">https://learn.sparkfun.com/tutorials/installing-an-arduino-bootloader#hardware-hookup</a></p>So Arduino’s brains is a ATmega328p microcontroller. On the standard Arduino Uno, it comes as a chip that you can remove from the board, so if you fry it on accident, you can replace just the chip instead of the whole board. So is it possible to remove all the stuff Arduino gives you, take just the chip, and directly program the ATmega328p? Well I came across a youtube playlist recently that gives a resounding yes, yes you can. Mitch Davis’ Bare-Metal MCU playlist walks you through taking all the helpful things Arduino gives you, and removing them one by one. This sort of content is exactly up my alley, and I realized I had an Uno kicking around, plus a sparkfun version of an Uno, a sparkfun redboard. Why not follow along?Netgear DM 200 Modem Breakdown - The Hardware Side2021-05-13T00:00:00+00:002021-05-13T00:00:00+00:00/blog/2021/5/13/netgear-dm-200-modem-breakdown-the-hardware-side<p>Now that I’ve <a href="/blog/2021/2/23/netgear-dm-200-modem-breakdown-the-software-side">poked around the software</a> side of things on my DM 200 modem, it’s now time to poke some hardware!</p>
<p><br /></p>
<hr />
<p><strong><em>This is a part of my series on taking apart the netgear DM 200 modem</em></strong></p>
<p>For more posts on this, see below</p>
<ol>
<li>
<a href="/blog/2021/2/23/netgear-dm-200-modem-breakdown-the-software-side">Netgear DM 200 Modem Breakdown - The Software Side</a>
</li>
<li>
<a href="/blog/2021/5/13/netgear-dm-200-modem-breakdown-the-hardware-side">Netgear DM 200 Modem Breakdown - The Hardware Side</a>
(You are Here)
</li>
</ol>
<hr />
<p><br /></p>
<p>First things first, get the case open. Happily, there’s a very obvious screw on the back of the case, and a standard TR8 torx screwdriver removes it. The next bit was less obvious, but I had the openwrt website to help out. I used some picks from my ifixit repair kit to pop open the side of the case, and voila, the PCB was revealed.</p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210309_113917.jpg" alt="Initial opening of router" />
Popping open the side</p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210309_113937.jpg" alt="The PCB revealed" />
The PCB revealed!</p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210310_095140.jpg" alt="Front of the PCB" />
Front of the PCB</p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210310_095156.jpg" alt="Back of the PCB" />
Back of the PCB</p>
<p>Before I could remove it from the case, I had to remove some clear molded plastic clipped over the top of it. The plastic redirects the LED lights from the board to the outside of the case, which feels very clever and very simple, a sign of good design in my books. Once that’s taken out, the board is secured by two more screws, also TR8, and then the board is freed.
The first obvious thing is the huge metal box, soldered into the middle of the board. I would guess that it’s ground for the board, since all electronics need a ground. And possibly it doubles as protection for some more sensitive chips? Looking at the back of the board, I can see things are soldered in underneath the metal casing, so that seems to support my hypothesis. I’m immediately tempted to try to desolder it to see what’s underneath, but I’m trying to minimize potential damage for now, so I’ll leave that for another time.
The next interesting thing is all these IC chips with mysterious letters and numbers stamped on them! I have a vague understanding you can find the chips based on these serial values, and then get the chip documentation online, which tells you what they do. So, lets start doing that!</p>
<h2 id="the-hardware">The Hardware</h2>
<h3 id="winbond">Winbond</h3>
<p>First, this rather large-ish chip that says “Winbond” in large letters.</p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210310_092222_HDR.jpg" alt="Winbond chip" /></p>
<p>From what I can tell it’s an 8-pin chip, and the writing is “Winbond 25064 FVSIG1618”. It’s a bit roughed up as you can see, so I’m kind of guessing, but that seems a good initial thing to google. After searching around a bit, I discover it may actually be W25Q64FVSIG, so that’s a Q, not a 0 like I thought. Jotrin has the product part (<a href="https://www.jotrin.com/product/parts/W25Q64FVSIG">https://www.jotrin.com/product/parts/W25Q64FVSIG</a>), but won’t give me the data sheet without making me sign up with them. Rude!
Happily, datasheetq.com has no such rules, and I found the data sheet there as well: <a href="https://www.datasheetq.com/datasheet-download/840460/1/Winbond/25Q64FVAIF">https://www.datasheetq.com/datasheet-download/840460/1/Winbond/25Q64FVAIF</a></p>
<p>The datasheet shows that it’s a particular type of W25Q64FVSSIG chip. Which is different from what the marking on the chip said. Searching through the datasheet, I found that a top marking of 25Q64FVSIG, means it is in package type SS in a SOIC-8 208mil form factor.</p>
<blockquote>
<p><strong>NOTE:</strong> SOIC stands for “Small Outline Integrated Circuit”. It’s a standardized way of packaging the circuits. SOIC-8 means it has 8 pins</p>
</blockquote>
<p>Now that I know all the fancy numbers, what the heck is it? It’s a flash memory, used to store, well, something, that they want to keep even when the power is off (flash is non-volatile, so it remembers things even with the power off). The datasheet says the chip operates on a single 2.7V to 3.6V power supply. It also says it supports SPI communications. I have a ch341a that I got from the Wild West Hackin’ Fest last year, and it supposedly can read 25 SPI flash with 8 pins. So I believe I could copy everything off the chip and see what’s on it? I see another project for me soon…</p>
<blockquote>
<p><strong>NOTE:</strong> SPI stands for “Serial Peripheral Interface”, it’s a synchronous and serial communication protocol setup that is very common for embedded systems things</p>
</blockquote>
<p>But before I get too deep with this chip, there’s still a couple others that look interesting.</p>
<h3 id="d12103-g-1628-black-box">D12103 G 1628 black box</h3>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210310_092245.jpg" alt="Mysterious chip" />
This chip is rude and doesn’t have a name!</p>
<p>Instead of a useful name branded on it, I get a JWD on a globe with stars. I had earlier stumbled across some IC identification websites, the main one being <a href="https://www.elnec.com/en/support/ic-logos/?method=logo">https://www.elnec.com/en/support/ic-logos/?method=logo</a>, but no dice. After googling around a while, I finally found it at <a href="https://lcsc.com/brand-detail/12354.html">https://lcsc.com/brand-detail/12354.html</a>. It says it’s the logo for Sichuan Jingweida Technology Group Co., Ltd. It also gives the list of its products:</p>
<blockquote>
<p>the company mainly produces network transformer, DC converter, filter network network interface (RJ45), power transformer, power inductor, SMD, widely used in on communication, household appliances, electrical industry, pen and other high-tech fields</p>
</blockquote>
<p>However, searching for D12103 G 1628 on the chip didn’t yield any datasheets or more info than that. I did find the company website and browse around there, but it seemed a dead end <a href="http://www.myjwd.com/">http://www.myjwd.com/</a>. Since this chip is right by the ethernet plug, I’m guessing it’s a network transformer or filter network interface mentioned on the lcsc website.</p>
<h2 id="connecting">Connecting</h2>
<p>Enough googling, I want to try to fry some electronics! Well, actually that’s the exact opposite of my goal. But I do want to connect directly to the PCB using the handy dandy pin out that they left on the board. I used two other blog posts, <a href="https://jcjc-dev.com/2016/04/08/reversing-huawei-router-1-find-uart">https://jcjc-dev.com/2016/04/08/reversing-huawei-router-1-find-uart</a> and <a href="http://www.devttys0.com/2012/11/reverse-engineering-serial-ports/">http://www.devttys0.com/2012/11/reverse-engineering-serial-ports/</a> as my guides.
The pin out has 4 pins, so I’m guessing it’s a UART port that was used for developers when working on the board.</p>
<blockquote>
<p>UART stands for “universal asynchronous receiver-transmitter”. It has a ground, receiver (shortened to Rx), transmitter (shortened to Tx), and a power pin.</p>
</blockquote>
<p>The two blog posts I linked to above give ways for determining which pin is which. One of the tricks they give is shining a flashlight through the board. This way, you can actually see the connections each pin has, and use that as an initial guess.</p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210310_100126.jpg" alt="4 pins on a PCB with a light shining behind them" /></p>
<p>It certainly doesn’t look like the pins in the other blog! There’s a square connection, two circles, and one that looks to have a dark line at the top, bottom, and sides. If it is a UART connection, then the two circles that look similar are probably the Rx and Tx pins, with the wonky looking ones are the ground and power. But how to find out which ones are which?</p>
<p>It’s time for some multimeter use!</p>
<h3 id="finding-ground-and-power">Finding Ground and Power</h3>
<p>First, figure out which pin is ground. My theory is that the large metal cover on part of the PCB is doubling as ground for this device. Why have a huge chunk of metal in a device if you’re not using it as ground? So that means I can use my multimeter’s continuity test to see which of the pins connects to the metal cover, and that’ll be my ground!</p>
<blockquote>
<p><strong>NOTE:</strong> a continuity test on a multimeter sets it so the multimeter will make a loud beep noise when the two probes are electronically connected to each other. You can touch the probes together directly to hear the noise, or, more usefully, two points on a piece of electronics. If it beeps, there’s a way for electricity to flow from one probe location to another. Useful for making sure electricity can even flow at all in your projects!</p>
</blockquote>
<p>Touching each of the pins, from left to right in the picture, gave me the following results:</p>
<ul>
<li>First pin - short blip, and then silent after</li>
<li>Second pin - nothin’</li>
<li>Third pin - nothin’</li>
<li>Fourth pin - constant noise</li>
</ul>
<p>I’ve found ground! The fourth pin, with connections in all four directions, is the ground. The short blip from the first pin was weird, but the blog posts mention that this can happen when you try to do a continuity test on the power pin. So tentatively, it’s power.</p>
<h3 id="finding-rx-and-tx">Finding Rx and Tx</h3>
<p>That’s about as far as I can go without powering on the modem. It’s time to turn it on! Hopefully the magic smoke stays on the inside.
I can still use my multimeter for this. Multimeters excel at measuring voltage (that’s kind of their main function), and the whole point of UART is bouncing voltage up and down on the transmitting pin in order to send data. So the plan: Connect my multimeter up to the non-ground pins one by one, and watch the voltage amount on my multimeter. If there’s one that fluctuates a lot, that’s probably the transmit pin.
According to the blog post <a href="http://www.devttys0.com/2012/11/reverse-engineering-serial-ports/">http://www.devttys0.com/2012/11/reverse-engineering-serial-ports/</a>, most data is sent when it first boots up. So I’ll be turning the modem off between each test. I also want to be monitoring the multimeter’s screen, not staring at the probes I’m holding on very tiny pins. So I grabbed some double sided alligator clip wires, to clip to the pins and the probes. And the board needed to be held steady, so I grabbed my third hand, and connected everything up. After all this setup, I was ready to go!</p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210310_103301.jpg" alt="Alligator clips on an unknown pin and ground" /></p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210310_103506.jpg" alt="the whole multimeter setup" /></p>
<p>Going pin by pin, I got the following results:</p>
<ul>
<li>Pin 1: steady 3.3 volt</li>
<li>Pin 2: variable between 3.3 and 2.4</li>
<li>Pin 3: steady 3.3 volts</li>
</ul>
<p>By guessing the Tx and Rx pins will have the same trace patterns, I came up with a final result:</p>
<ul>
<li>Pin 1: Power</li>
<li>Pin 2: Tx</li>
<li>Pin 3: Rx</li>
<li>Pin 4: Ground</li>
</ul>
<p>Now that I’ve done all this, I need to actually connect to the pins. Luckily, I have a <a href="http://dangerousprototypes.com/docs/Bus_Pirate">bus pirate</a> just sitting around, which supports UART communications!</p>
<h3 id="using-the-bus-pirate">Using the bus pirate</h3>
<p>I may do a separate post later about how I did initial set up for the bus pirate. I used the graphic at <a href="https://learn.sparkfun.com/tutorials/bus-pirate-v36a-hookup-guide">https://learn.sparkfun.com/tutorials/bus-pirate-v36a-hookup-guide</a> to figure out which color wire should connect to which pin on the modem.</p>
<p>Connect:</p>
<ul>
<li>Rx of bus pirate (black wire) to Tx of router (pin 2)</li>
<li>Tx of bus pirate (grey-ish wire) to Rx of router (pin 3)</li>
<li>Ground of bus pirate (brown, kinda, wire) to ground pin (pin 4)</li>
</ul>
<p>I don’t need to connect the power pin because I won’t be powering the modem, I’ll let it stay plugged in like normal.</p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210311_103550.jpg" alt="bus pirate-modem connection" /></p>
<p><img src="/assets/netgear-dm-200-modem-breakdown-the-hardware-side/20210311_103542.jpg" alt="the set up" /></p>
<p>One last aspect of UART is that it has a specific baudrate that different UART connections use to communicate. How do you know which rate to use? Well, you don’t. There’s a bunch of standard ones, though, so I guessed during the setup of my bus pirate, and managed to get it right the first try!</p>
<p>With the bus pirate plugged into my computer, I used the <code class="language-plaintext highlighter-rouge">screen</code> command to connect to it.</p>
<blockquote>
<p><strong>NOTE:</strong> when using <code class="language-plaintext highlighter-rouge">screen</code>, you can enter <code class="language-plaintext highlighter-rouge">Ctrl+a</code> then <code class="language-plaintext highlighter-rouge">H</code> to log output of screen into a screenlog.0 file. I did this so I can review all the output of the modem later</p>
</blockquote>
<p>The bus pirate talks to my computer at a baudrate of 115200, and the USB connection was at /dev/ttyUSB0, so to connect to the bus pirate from my computer I typed:</p>
<p><code class="language-plaintext highlighter-rouge">screen /dev/ttyUSB0 115200</code></p>
<p>In bus pirate, I changed the mode to UART and set connection requirements. Once that was done, I turned on the modem and waited for something to happen. Below is a capture of the screen while setting up, then what happens once it’s turned on (bus pirate set up ends with the line that just says “Ready”)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HiZ>m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)
(1)>3
Set serial port speed: (bps)
1. 300
2. 1200
3. 2400
4. 4800
5. 9600
6. 19200
7. 38400
8. 57600
9. 115200
10. BRG raw value
(1)>9
Data bits and parity:
1. 8, NONE *default
2. 8, EVEN
3. 8, ODD
4. 9, NONE
(1)>1
Stop bits:
1. 1 *default
2. 2
(1)>1
Receive polarity:
1. Idle 1 *default
2. Idle 0
(1)>1
Select output type:
1. Open drain (H=Hi-Z, L=GND)
2. Normal (H=3.3V, L=GND)
(1)>2
Ready
ROM VER: 1.1.4
CFG 05
ROM VER: 1.1.4
CFG 05
DDR autotuning Rev 1.0
DDR size from 0xa0000000 - 0xa3ffffff
DDR check ok... start booting...
U-Boot 2010.06-12284-ga4702df (Mar 03 2016 - 13:07:38)
DM200 (hw29765233p8p0p64p0p0) UBoot-v2010.06 dni1 V0.9
CLOCK CPU 500M RAM 250M
DRAM: 64 MiB
In: serial
Out: serial
Err: serial
8192 KiB W25Q64 at 0:3 is now current device
Net: Internal phy(FE) firmware version: 0xc434
vr9 Switch
.
.
.
This goes on for a while, I'm stopping it here
</code></pre></div></div>
<p>It works! Cue dancing around and pumping my fists victoriously. Now, I have no idea what to <em>do</em> with all this info spewing on my screen, but this is the first time I’ve done any sort of reverse engineering of hardware, so I think I deserve to celebrate.</p>
<p>After I let it continue to spew mysterious log info for a while, it finally settles down, and gives me root busybox access! However, it’s not all fun and games. The modem is not happy about not being able to complete the PPPoE discovery, and periodically just throws it into my shell as I try to type. I tried a few commands, but got a bit annoyed at the extra info popping up.</p>
<blockquote>
<p><strong>NOTE:</strong> PPPoE stands for “Point-to-Point Protocol over Ethernet”. It’s used by most DSL providers for authentication and encryption purposes. It’s for sending packets to the ISP’s network before going to the rest of the internet, from what I can tell on wikipedia.</p>
</blockquote>
<p>This is a DSL modem, and it’s not connected to any internet, so I’m guessing that’s why it fails. I could potentially work around that, but honestly, I’m not sure what all I can do from here, so I’m leaving it alone. Here’s the output of the shell and my attempts at playing around.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Timeout waiting for PADO packets
Unable to complete PPPoE Discovery
Timeout waiting for PADO packets
Unable to complete PPPoE Discovery
Timeout waiting for PADO packets
Unable to complete PPPoE Discovery
starting pid 345, tty '/dev/ttyLTQ0': '/bin/ash --login'
BusyBox v1.17.1 (2016-04-29 07:02:59 EDT) built-in shell (ash)
Enter 'help' for a list of built-in commands.
+---------------------------------------------+
| Lantiq UGW Software UGW-6.1.1 on XRX200 CPE |
+---------------------------------------------+
root@DM200:/# [ 446.710000] DSL[00]: ERROR - Function is only available in the SHOWTIME!
[ 446.740000] DSL[00]: ERROR - Function is only available in the SHOWTIME!
ftpput: can't connect to remote host (60.248.155.55): Network is unreachable
Timeout waiting for PADO packets
Unable to complete PPPoE Discovery
root@DM200:/# whoami
/bin/ash: whoami: not found
root@DM200:/# ls
bin hardware_version ramdisk_copy
default_language_version hw_id rom
dev lib root
etc mnt sbin
firmware module_name sys
firmware_region opt tmp
firmware_time overlay usr
firmware_version proc var
flash ramdisk www
root@DM200:/# Timeout waiting for PADO packets
Unable to complete PPPoE Discovery
c[J
root@DM200:/# cat hardware
root@DM200:/# cat hardware_version
DM200
root@DM200:/# cat hw_id
29765233+8+0+64+0+0
root@DM200:/# cat firmware_v
root@DM200:/# cat firmware_version [J
V1.0.0.34
root@DM200:/# ls /bin
adduser dmesg mkdir rmdir
ash dnsdomainname mknod sed
busybox echo mount sh
busybox2 egrep mv sleep
cat fgrep netstat su
chgrp getopt nice sync
chmod grep nvram tar
chown gunzip pidof touch
config gzip ping true
cp hostname ping6 umount
datalib ipcalc.sh ps uname
date kill pwd usleep
dd ln readycloud_nvram vi
deluser login.sh rev zcat
df ls rm
root@DM200:/# Timeout waiting for PADO packets
Unable to complete PPPoE Discovery
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>There you have it, my first hardware reverse engineering adventure! I certainly learned a lot about datasheets, integrated circuit logos, some cool ways to use multimeters, basics of how a router/modem is set up, UART, AND basics of using bus pirate. Whew!</p>
<p>This was super fun, and slightly nerve-wracking, which I think means it’s something I should do more of. My other pieces of hardware are no longer safe from my prying eyes and screwdrivers!</p>Now that I’ve poked around the software side of things on my DM 200 modem, it’s now time to poke some hardware!Netgear DM 200 Modem Breakdown - The Software Side2021-02-23T00:00:00+00:002021-02-23T00:00:00+00:00/blog/2021/2/23/netgear-dm-200-modem-breakdown-the-software-side<p>Motivated by miscellany blog posts, I decided to try my hand at poking around an old modem I had lying around. </p>
<p><br /></p>
<hr />
<p><strong><em>This is a part of my series on taking apart the netgear DM 200 modem</em></strong></p>
<p>For more posts on this, see below</p>
<ol>
<li>
<a href="/blog/2021/2/23/netgear-dm-200-modem-breakdown-the-software-side">Netgear DM 200 Modem Breakdown - The Software Side</a>
(You are Here)
</li>
<li>
<a href="/blog/2021/5/13/netgear-dm-200-modem-breakdown-the-hardware-side">Netgear DM 200 Modem Breakdown - The Hardware Side</a>
</li>
</ol>
<hr />
<p><br /></p>
<p>It’s a netgear DM200, ADSL/VDSL modem/router (I will be calling it either a router or modem in this blog post, depending on my mood). My plan is first do some recon and poking the software, without opening up or doing any hardware shenanigans. Once I have a grip on what’s happening, I’ll then open it up and see if I can do some lower-level reverse engineering. So let’s get started!</p>
<h2 id="exploring-firmware">Exploring Firmware</h2>
<p>I pulled the current version of the firmware from their website:
<a href="https://www.netgear.com/support/product/DM200.aspx#download">https://www.netgear.com/support/product/DM200.aspx#download</a>. The firmware is actually a complete copy of the software running on the modem, so I can play with that and get a somewhat accurate look at what’s currently running on my modem. Since I haven’t updated the firmware on the physical modem I have, the version I downloaded online may be a newer version than what is currently on it, but it can give me some initial info and hypothesis I can use later. </p>
<p>Since I had recently played around with the Swag Bag Lab from wild west hackin’ fest (
<a href="https://wildwesthackinfest.com/deadwood/sbl-instructions">https://wildwesthackinfest.com/deadwood/sbl-instructions</a>), I knew binwalk was a reverse engineering tool you could use in linux, so I started with that.</p>
<p>After I downloaded the image, I used the below command to find out more about the .img file I got.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Downloads/DM200_V1.0.0.66$ binwalk --signature --term ./DM200-V1.0.0.66.img
</code></pre></div></div>
<p><strong>Explanation</strong>
–signature flag is for finding signature of file types in img, –term to resize to fit the terminal window. Binwalk goes through the file and looks for special signatures that denote a particular file type. Blog post here describes it:
<a href="https://embeddedbits.org/reverse-engineering-router-firmware-with-binwalk">https://embeddedbits.org/reverse-engineering-router-firmware-with-binwalk</a></p>
<p>The binwalk command gave me this (apologies for the bad formatting):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DECIMAL HEXADECIMAL DESCRIPTION
---------------------------------------------------------------------------------------------------------------------------------------
128 0x80 uImage header, header size: 64 bytes, header CRC: 0x5BEA65A6, created: 2020-08-11 07:24:23, image size:
1625568 bytes, Data Address: 0x80002000, Entry Point: 0x8000A970, data CRC: 0x8FE0035E, OS: Linux, CPU:
MIPS, image type: OS Kernel Image, compression type: lzma, image name: "MIPS LTQCPE Linux-3.10.12"
192 0xC0 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 4872776 bytes
1638464 0x190040 uImage header, header size: 64 bytes, header CRC: 0x4458CD93, created: 2020-08-11 07:24:32, image size:
475136 bytes, Data Address: 0x40908000, Entry Point: 0x40908000, data CRC: 0xE383D3B5, OS: Linux, CPU:
MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux-3.10.12"
1638528 0x190080 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 474431 bytes, 3 inodes,
blocksize: 131072 bytes, created: 2020-08-11 07:24:31
2162752 0x210040 uImage header, header size: 64 bytes, header CRC: 0xA33A8813, created: 2020-08-11 07:24:32, image size:
5148672 bytes, Data Address: 0x40908000, Entry Point: 0x40908000, data CRC: 0xAAF2E52, OS: Linux, CPU:
MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux-3.10.12"
2162816 0x210080 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 5147702 bytes, 2308 inodes,
blocksize: 131072 bytes, created: 2020-08-11 07:24:30
</code></pre></div></div>
<p>So I can see it uses a MIPS Linux, presumably the version listed as “Linux-3.10.12”. I hadn’t heard of MIPS linux before so I had to do some research. MIPS is an instruction set, and MIPS Linux is a Linux distro that is compiled for MIPS. So similar to ARM architecture, but MIPS is used more for routers and gateways. Funnily enough, according to wikipedia, the N64, Playstation 1 and 2, and the PSP all used MIPS! </p>
<p>It also uses squashfs, which wikipedia says: is a compressed read-only file system for Linux. Squashfs can be uncompressed with binwalk, and I can then poke around at the filesystem of the MIPS linux without actually running any linux kernels or hacking into the modem’s system or anything.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Downloads/DM200_V1.0.0.66$ binwalk -Me DM200_V1.0.0.66.img
</code></pre></div></div>
<p><strong>Explanation:</strong>
-e means extract the files found by binwalk (including extracting the squashfs), -M means do it recursively (stands for Matroyshka, a la matryoshka dolls, I assume)</p>
<p>Once binwalk finishes, I can continue my poking! I didn’t have tons of ideas of what to look for specifically, so I was using various blog posts to spark ideas. One was looking for a /etc/banner to find out more about the linux distro (which they do here:
<a href="https://embeddedbits.org/reverse-engineering-router-firmware-with-binwalk/">https://embeddedbits.org/reverse-engineering-router-firmware-with-binwalk/</a>) </p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Downloads/DM200_V1.0.0.66$ cd _DM200-V1.0.0.66.img.extracted/
~/Downloads/DM200_V1.0.0.66/_DM200-V1.0.0.66.img.extracted$ cd squashfs-root0
~/Downloads/DM200_V1.0.0.66/_DM200-V1.0.0.66.img.extracted/squashfs-root-0$ cat ./etc/banner
+---------------------------------------------+
| Lantiq UGW Software UGW-6.1.1 on XRX200 CPE |
+---------------------------------------------+
</code></pre></div></div>
<p>Well that seems like a bunch of gibberish. DuckDuckGo to the rescue! Looks like Lantiq was a semiconductor company bought out by Intel in 2015. They manufactured SoC (system on chip) for home networking. So I bet then if I open up this modem it’ll have a Lantiq chip inside. That’s cool, I can tell just by looking at some software!</p>
<p>Just searching for the string “Lantiq UGW Software UGW-6.1.1 on XRX200 CPE” led me to the website openwrt:
<a href="https://openwrt.org/toh/netgear/dm200">https://openwrt.org/toh/netgear/dm200</a>. They have lots of info about this particular router. OpenWrt is a linux operating system targeting embedded devices. The page I got is explaining how to replace the default firmware that Netgear puts in it with the OpenWrt software. It also has a hardware section that shows me a serial pinout and the order of the pins. Sweet! So when I open it up, I can try to connect my bus pirate or ch341a to try to get access to the modem’s code directly! At least I think I can use either of those for this purpose. I haven’t done it before, so I guess I’ll find out later.</p>
<p>Another useful section is the Misc section, where it mentions there’s an advanced debug page accessible in the router’s website at http://192.168.5.1/debug.htm. Most routers and modems normally host their own websites that end users can log into to modify various router settings (wifi, passwords, etc.). Now I know the IP that the website will probably be hosted on when I plug it in. And apparently the debug page lets you toggle on telnet access to the router. So I won’t even have to open it up to start mucking with the OS running on my modem. </p>
<p>However, I don’t want to take random internet sites at face value, so I decide to double check the firmware to see if there is such a debug.htm file. I noticed in the firmware’s file system there’s a www folder. That’s a common folder to host a website at, and when I open it up, sure enough, there’s a bunch of htm files. So a quick look for a debug.htm…</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Downloads/DM200_V1.0.0.66/_DM200-V1.0.0.66.img.extracted/squashfs-root-0/www$ ls | grep debug
collect_debug.txt
debug.cgi
debug_cloud.cgi
debug_detail.htm
debug.htm
debuginfo.htm
debug_run.htm
NTP_debug.htm
</code></pre></div></div>
<p>Bam jackpot, debug.htm. Plus a bunch of other files I may want to take a look at. Almost time to plug in my modem!</p>
<p>But first I had a question. A lot of the router reverse engineer blog posts I saw mentioned busybox, a software suite that provides several Unix utilities in a single executable file. But so far I haven’t seen anything that says busybox on it. Executables are stored in /bin, so I took a peek to see what sort of executables this filesystem has:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Downloads/DM200_V1.0.0.66/_DM200-V1.0.0.66.img.extracted/squashfs-root-0$ ls bin
adduser chgrp datalib dmesg getopt ipcalc.sh mkdir nice ps rmdir sync uname
ash chmod date dnsdomainname grep kill mknod nvram pwd sed tar usleep
busybox chown dd echo gunzip ln mount pidof readycloud_nvram sh touch vi
busybox2 config deluser egrep gzip login mv ping rev sleep true zcat
cat cp df fgrep hostname ls netstat ping6 rm su umount
</code></pre></div></div>
<p>Ah, there’s busybox! There’s also two executables that still have .sh after them, representing shell scripts. Those look custom, maybe just for this modem? Reading through them, the ipcalc literally seems a way to figure out the ip start and end range and other IP calculation work. Which makes sense for a router. I’m unsure what the login.sh is for. Though I do see at the start there’s a comment:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Copyright (C) 2006-2011 OpenWrt.org
</code></pre></div></div>
<p>Hey, that’s the website from earlier! So maybe Netgear or Lantiq started with a copy of OpenWrt and then modified it for their modem? More questions to try to answer!</p>
<p>There’s a lot of other searching I can do, but for now, I think the next best step is to actually connect to the modem, and see if I can get telnet up like OpenWrt mentions. </p>
<h2 id="connecting-to-the-modem">Connecting to the Modem</h2>
<p>The router I had lying around included the box and default cables, so I could use the included ethernet cable to connect to my laptop, and the power cord to turn it on, and I was off to the races.</p>
<p>First step was to hit the URL I found earlier and try to turn on telnet</p>
<p><img src="/squarespace_images/Screenshot.png" alt="Screenshot.png" /></p>
<p>It requires me to give it a username and password, but looking at the manual online
<a href="https://www.downloads.netgear.com/files/GDC/DM200/DM200_UM_EN.pdf">https://www.downloads.netgear.com/files/GDC/DM200/DM200_UM_EN.pdf</a>, I can see that the username and password is most likely admin/password. Type that, and I’m in! There’s the handy “enable telnet” button. Once that’s turned on, I connect from my laptop using telnet and voila, I’m dropped into a shell, no password required!</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BusyBox v1.17.1 (2016-04-29 07:02:59 EDT) built-in shell (ash)
Enter 'help' for a list of built-in commands.
/ # help
Built-in commands:
------------------
. : [ [[ alias bg break cd chdir command continue eval exec exit
export false fg hash help jobs kill let local printf pwd read
readonly return set shift source test times trap true type ulimit
umask unalias unset wait
</code></pre></div></div>
<p>Cool, so there’s some built-in commands, and it says right at the top it’s running BusyBox from 2016. That makes sense, this router/modem was released in 2016. </p>
<p>I did try some standard bash commands (ls, cat) and they seem to work though, so it looks like that help isn’t quite accurate. I looked in the /bin folder, and it looks like all the standard bash commands are there. So I can still use all my linux bash-fu to poke around in the software. </p>
<p>Because a lot of the blogs I found focused on finding vulnerabilities in the firmware, they all suggest hunting for things like passwords in plain text. I ran some grep commands hunting for passwords, but didn’t find anything good. I tried some other greps and nothing else really popped. So I moved on to exploring /etc and /var. The /etc folder normally has lots of configuration files and the like, so it can be an interesting place to explore. The /var folder stores logs, and it can reveal info like the sort of processes being run. </p>
<p>Running through the etc folder I came across some interesting configuration files. Here’s a quick rundown of some of the files</p>
<p><strong>OpenWrt</strong></p>
<p>I found a couple files, openwrt_version and openwrt_release, which confirms this modem/router is running a customized copy of OpenWrt. Interestingly enough, OpenWRT 12.09 came out in 2013 in April, even though this modem came out in 2016. So on release it was already running a 3 year old version of OpenWrt. I’ve heard that a lot of modems and routers are like this, where offcial copies of firmware are often running on out of date (and therefore often insecure) software, but it’s good to see confirmation myself!</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc # cat openwrt_version
12.09
/etc # cat openwrt_release
DISTRIB_ID="OpenWrt"
DISTRIB_RELEASE="Attitude Adjustment"
DISTRIB_REVISION="12.09_ltq"
DISTRIB_CODENAME="attitude_adjustment"
DISTRIB_TARGET="lantiq/xrx200"
DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09"
</code></pre></div></div>
<p><strong>Device Info</strong></p>
<p>Opening up /etc/sys.conf, I could see for myself some more confirmation it was manufactured by Lantiq Communications. The lantiq.com link now goes to the home page of intel, since they were bought out. Also, it’s kind of funny, this modem was released in 2016 and says it was made by Lantiq, but Lantiq was already bought out by Intel by that point (since it was bought in 2015). So this router must have been released in that weird in-between time after a company is bought out by another. </p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc # cat sys.conf
#<< device_info
device_info_manu="Lantiq Communications"
device_info_oui="AC9A96"
device_info_modname="UT300R2U"
device_info_friendlyname="xDSLRouter"
device_info_prodclass="CPE"
device_info_sernum="DMA66"
device_info_specver="1.0"
device_info_modnum="1.0"
device_info_tr64url="http://www.lantiq.com"
#>> device_info
</code></pre></div></div>
<p><strong>“Encoded” Passwords</strong></p>
<p>One of the files I found looks to contain configuration info for the DSL connection back to the ISP. There it was the old username of the person who owned this modem last (my parents), as well as their password for the ISP, that was “encoded” using base64. The conn_type of “pppoe” I’m assuming is setting the connection type from my modem to the ISP, and is referencing “Point-to-Point Protocol over Ethernet”. Wikipedia explains this protocol is the solution for tunneling packets over the DSL connection to the ISP’s IP network, and from there to the rest of the Internet. I’m guessing this is the username and password that they would also use to sign in to the ISP’s website to pay their bill and update their internet connection. This seems like a bad set up to me, since base64 isn’t really an encryption, and the big rule for passwords is always hash and salt them, but hey, I’m not a huge corporation that was bought by Intel, so what do I know?</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc # cat lantiq_dsl_wan.conf
cfg_wan_mode="adsl_atm"
cfg_conn_type="pppoe"
cfg_vlan=""
cfg_pri=""
cfg_vpi="0"
cfg_vci="35"
cfg_encaps="llc"
cfg_qos=""
cfg_username="DSL USERNAME"
cfg_password="PASSWORD IN BASE64"
</code></pre></div></div>
<p><strong>No Hacker Protection, sadly</strong></p>
<p>One configuration file that just had TONS of info in it was the rc.conf file. I browsed through it quickly, since I mostly didn’t know what I was looking for, but did find some interesting sections. My personal favorite is this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ENABLE_HACKER_ATTACK_PROTECT="0"
</code></pre></div></div>
<p>Presumably “0” is false, so this modem/router is not protected from hackers. All well, more fun for me!</p>
<p><strong>System Password in plain text?</strong></p>
<p>Another section that looks worrying is this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#<< system_password ##56
Password="admin"
PasswdProtect="0"
#>> system_password
</code></pre></div></div>
<p>The Protect variable is presumably set to false, so the fact this password is clearly in plain text isn’t an issue for now, but that seems bad. Also, I’m not sure what system password this is referring to, so far the only password I had to type in was “password”, which netgear tells me about. Maybe it’s for if I want to add a password to root later?</p>
<p><strong>FTP users?</strong></p>
<p>Still in rc.conf, I find below. That looks an awful lot like something you’d see in a /etc/passwd or /etc/shadow. When I had read the OpenWrt page on this, the misc. Section talked about a plain text FTP username and password. There’s a script that uploads log files to a specific IP address, and it has hardcoded, plain text username and password. I’m guessing that’s the same user as this one. Also…not great. I didn’t check out the IP or try the username or password because that seems stupid to do, but according to OpenWrt, malware has been uploaded in all places people can reach, which seems consistent with the internet. </p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#<< password_file ##120
passFileLineCount='1'
passFileLineCount0='ftp:[mysterious gibberish, possibly hashed password]:100:100:ftp:/tmp:/dev/null'
#>> password_file
</code></pre></div></div>
<p><strong>Remember when Yahoo was big?</strong></p>
<p>I have no idea what this section does, but I’m entertained there’s some hardcoded Yahoo variables. Why does a modem need to know about YAHOO_STATUS and ports? </p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#<< dos_applications ##280
HOTSYNC_STATUS="0"
HOTSYNC_PORT="14238"
OLD_HOTSYNC_PORT="14238"
YAHOO_STATUS="0"
YAHOO_PORT="5010"
OLD_YAHOO_PORT="5010"
MIME_STATUS="0"
MIME_PORT="25"
OLD_MIME_PORT="25"
CODERED2_STATUS="0"
CODERED_STATUS="0"
ICQ_STATUS="0"
WEB_PORT="80"
OLD_WEB_PORT="80"
#>> dos_applications
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>Well that’s all the poking around I’ve done so far, and the interesting things I’ve found. Next up, opening up the modem and trying to identify some hardware and what it does. Plus, trying to connect to it using the serial connection ports like a hardware dev, and trying not to fry anything too important!</p>
<p><strong>References</strong></p>
<p>Want to see more firmware and modem/router reversing? Here’s a list of the blog posts I found useful:</p>
<p><a href="https://jcjc-dev.com/2016/04/08/reversing-huawei-router-1-find-uart">https://jcjc-dev.com/2016/04/08/reversing-huawei-router-1-find-uart</a> Focused on the physical hardware side more than exploring the firmware, but super helpful for learning about the basics of poking at hardware!</p>
<p><a href="https://simonfredsted.com/996">https://simonfredsted.com/996</a> Focused more on firmware side of things</p>
<p><a href="https://embeddedbits.org/reverse-engineering-router-firmware-with-binwalk">https://embeddedbits.org/reverse-engineering-router-firmware-with-binwalk</a> Also firmware, talks a lot about binwalk and its uses</p>Motivated by miscellany blog posts, I decided to try my hand at poking around an old modem I had lying around.