tag:blogger.com,1999:blog-38974011185001094182024-03-13T15:17:10.713-04:00DoodleTsA blog for various doodles, tips, and tricks of embedded Linux development.TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.comBlogger69125tag:blogger.com,1999:blog-3897401118500109418.post-83940584055641025422024-01-03T12:49:00.000-05:002024-01-03T12:49:30.295-05:00Ethernet-Over-Power (aka powerline ethernet)<div class="separator"><p style="margin-left: 1em; margin-right: 1em;"> </p></div><p>Imagine you have a piece of electronics equipment that you want to install somewhere. The device will need power and perhaps networking. Power can be supplied from a nearby outlet or batteries. Networking can be provided wirelessly, or by running wires to the location. Chances are most areas of your home already have outlets nearby, available networking might be a different story. Running ethernet to a location can be expensive and messy, especially if you want to "do it right" by running it inside the walls, using faceplates, and making everything look nice. Wireless sounds great in theory, but is often tricky to get working reliably in practice. Ethernet-over-power (aka powerline ethernet) is a way of using the existing power lines to also carry the networking data; removing the need to run ethernet to, or setup a wireless connection at, locations that already have power but no networking.</p><p>Not to be confused with power-over-ethernet (PoE) which is the exact opposite scenario in which you have a location that has ethernet but no power outlet. PoE allows you to transmit power (upwards of 71 watts) as well as network data over the ethernet cable; removing the need to run power to locations that already have ethernet but not power.</p><p>Our house was built in the early 1970's and doesn't have wired ethernet. Most people can solve this problem with WiFi. WiFi works somewhat for us, but not very well. The original house was built with 16" thick granite stone walls, then in 2001 an addition was built. So now the house is quite long, with a 16" stone wall in the middle. Including the garage, our entire house is about 100' long by 30' wide.<br /></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC49SA8pTw2QIuNnhDsEUzzPIArCybKwK_6VyEHpR1yPeCV3z_yDpwWBUVe5b8iPJnz3Fb7caEqYWYxcRbz4_R-Pav2OtNEJaDY7tCr9iFB885ABHcGdjgUaIROt6rlbIXSOGa40h-RDJiebxCQmPYP9frJXgbBr6HI4rb5xNs9ctB5XXGM06wm-b5/s673/eth-over-power.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="226" data-original-width="673" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC49SA8pTw2QIuNnhDsEUzzPIArCybKwK_6VyEHpR1yPeCV3z_yDpwWBUVe5b8iPJnz3Fb7caEqYWYxcRbz4_R-Pav2OtNEJaDY7tCr9iFB885ABHcGdjgUaIROt6rlbIXSOGa40h-RDJiebxCQmPYP9frJXgbBr6HI4rb5xNs9ctB5XXGM06wm-b5/s16000/eth-over-power.png" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p>When we first moved in, we setup WiFi. Currently WiFi comes in 2 different bands: 2.4GHz and 5GHz. 2.4GHz is slower, but travels further and through more things; 5GHz is faster, but has a shorter range and doesn't go through walls as easily (especially walls made with 16" of granite). Setting up the WiFi router in the original house at 2.4GHz works okay for some areas of the original house and barely works in the addition. Setting up the WiFi router in the original house at 5GHz barely works in the original house, and not at all in the addition. Conclusion: WiFi isn't that great. At a minimum, in order to get it working halfway decent, I would need to install a bunch of repeaters throughout the house. Getting WiFi repeaters to work well and seamlessly isn't easy (although the situation is improving with the move to mesh networking).<br /></p><p></p><p>Incorporating users' reviews into research on any topic can be a dicey proposition, and the user reviews of ethernet-over-power did not disappoint in that regard! Some people claimed that it worked perfectly, others said it didn't work at all. Some people said that they could "hear" the devices from their neighbours' ethernet-over-power setups, others said they couldn't communicate with their own devices from one side of a given room to the other. Some people claimed that ethernet-over-power signals could not cross an electrical panel, others said it crossed just fine. Some people claimed that all the devices you wanted to connect together had to be connected to the same side of a given electrical panel, others said no such restriction existed. Reading, and interpreting, customer reviews is an art onto itself, so
it's hard to know if some of those bad reviews are actual limitations of
the technology, or bad products, or faulty devices, or customers doing
something wrong, or perhaps customers not understanding. Perhaps it was a
case of older technology versus newer?</p><p>When we first moved in I had discovered ethernet-over-power and hoped it
was a cheap solution to all my problems. But all these contradictory reports caused me to drop it from consideration back then.</p><p>More recently I was chatting with a co-worker about such things and he mentioned ethernet-over-power as a great solution that he himself was using. I mentioned that I had investigated it a while back and dismissed it, but he assured me that it worked great. I asked him about "same side of the panel" issues, I asked him about "crossing a panel" issues, I asked about "hearing the neighbours", and everything else I could remember. He said none of those issues existed and that it worked fine for him. In any case, based on his recommendation I bought a couple units and gave it a try.</p><p>Today as I write this entry I have been using ethernet-over-power for just over a year. I'm currently in the process of running ethernet wires around the entire property so I can get rid of ethernet-over-power. It doesn't work well for me, but that doesn't mean it won't work well for you.</p><p>I've purposefully avoided saying which exact brand and products I'm using. My guess is they all work somewhat the same. Short-comings that I find in one are probably present in the others, and things that work well in one are probably similar to features in others. It's probably also worth noting that all the devices that I bought come from the same company. In fact I bought all the same specific products, except for one device which still came from the same company, but was a 2-jack version of the same device. Therefore I don't think that the reason why it doesn't work well for me is because I chose one company over another, or one product over another, or because I mixed products from different manufacturers. There are limitations to the technology itself which I believe are the root of my issues. Perhaps a competitor's product would have worked slightly better, or maybe slightly worse, but in the end I don't think ethernet-over-power was ever going to solve my issues.</p><h3 style="text-align: left;">Ethernet-Over-Power Basics<br /></h3><p>Starting with a house that has an ethernet network, and a network of power wires:</p><p> <br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIqgKM9yfCeBJihSKkIPNY6TWSyYG52QbnweDc62PPc9pY34wFFHX1grj8nXxYFtKBSeNVV0o_liT_sQUxpSAeOL4qhY6qzn2Kd7nMCRn8Eq7c9YeU_5JxFdCbUXg7BZqwPeoPO4mQxw8_A8I-G4vNICTATXcS2Xm14ETOXUj1V7nV-KzMRst7qgkI1Uo/s608/network-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="346" data-original-width="608" height="364" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIqgKM9yfCeBJihSKkIPNY6TWSyYG52QbnweDc62PPc9pY34wFFHX1grj8nXxYFtKBSeNVV0o_liT_sQUxpSAeOL4qhY6qzn2Kd7nMCRn8Eq7c9YeU_5JxFdCbUXg7BZqwPeoPO4mQxw8_A8I-G4vNICTATXcS2Xm14ETOXUj1V7nV-KzMRst7qgkI1Uo/w640-h364/network-1.png" width="640" /></a></div><br /><p></p><p></p><p>The ethernet network can only be "injected" once into the power wires at one point; loops cause the network to go haywire.</p><p></p><p></p><p></p> <p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBwgq7YdrDJ5VbhlRGsFRwAK87HyFxniH8Mhqthijfgh0eNGoXnlfo_7herkWRYqSPG0uataLtEik92hDXSN_KoaSYB50iH7JR5Y4wjc7_eD2aUzKketIXRi2Wx_K02P6Ybzm0k5AY2WCbo04ViHSz7KDTxxwVau3BQ2sCkpR4hFnwtSc33RYK5W7803Y/s582/network-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="326" data-original-width="582" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBwgq7YdrDJ5VbhlRGsFRwAK87HyFxniH8Mhqthijfgh0eNGoXnlfo_7herkWRYqSPG0uataLtEik92hDXSN_KoaSYB50iH7JR5Y4wjc7_eD2aUzKketIXRi2Wx_K02P6Ybzm0k5AY2WCbo04ViHSz7KDTxxwVau3BQ2sCkpR4hFnwtSc33RYK5W7803Y/w640-h358/network-2.png" width="640" /></a></div> <p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRT-xh53-XJkiDQac3Cb-y9c7_XB1IuN0Y_-Xs3kOy8OaMuxq_qzzI25d5cTr-UyP_874BqXptWnFkgQB_srTmUL9fd7N8qgY_sdMru7yfILp6uECLYXTrEOyLUs_MbJliGA5eH1zoSnsvVx_I3RLR80xMR59HBPYhBtaOV8pvTen1MU-zdxzzQepWQv0/s582/network-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="337" data-original-width="582" height="370" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRT-xh53-XJkiDQac3Cb-y9c7_XB1IuN0Y_-Xs3kOy8OaMuxq_qzzI25d5cTr-UyP_874BqXptWnFkgQB_srTmUL9fd7N8qgY_sdMru7yfILp6uECLYXTrEOyLUs_MbJliGA5eH1zoSnsvVx_I3RLR80xMR59HBPYhBtaOV8pvTen1MU-zdxzzQepWQv0/w640-h370/network-3.png" width="640" /></a></div><br /><p></p><p>Any number of leaf devices can be attached to the power network, but the "only
be one bridge" rule must be maintained.</p><br /><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTt2QZCLIH8iyHQMxlgNurZxDr1jdxEwkXlOU4nFYT9L0sSonT9o2CIHqm64xse8wkTn-c1AFlwfngSx6O9kEOd2RkgQ9u_vg-vKsWZbS_eCIi74ziba5d9bUcNGOROu6_d3BvcWXYAkTO-4MC0FXhUN3g2vcUM9CNjpyW2o0C1AjWzo5-xiKpyVPOJ8k/s582/network-4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="299" data-original-width="582" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTt2QZCLIH8iyHQMxlgNurZxDr1jdxEwkXlOU4nFYT9L0sSonT9o2CIHqm64xse8wkTn-c1AFlwfngSx6O9kEOd2RkgQ9u_vg-vKsWZbS_eCIi74ziba5d9bUcNGOROu6_d3BvcWXYAkTO-4MC0FXhUN3g2vcUM9CNjpyW2o0C1AjWzo5-xiKpyVPOJ8k/w640-h328/network-4.png" width="640" /></a></div><br /><p></p><p></p><p>It is even possible to have networking equipment "after" the ethernet-over-power network. Just make sure the rule requiring only one bridge is maintained.</p><p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzFYGVUzVPd0zvADNqW-LENz-HPbZE3LfSREudQfGzqGKsYkEunlnPW7C0jt0vnXipKLq_678OQljM5LNpK3INHGRk74lq_2UnPI2anprfelwNxCrrRN9NtaY6569UtYdD6RuFg8jmgykZbiHLHjyYLrJc0hbx-REd-yrJ9UAbj8xdoywqzwkx3EtkKUk/s582/network-5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="299" data-original-width="582" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzFYGVUzVPd0zvADNqW-LENz-HPbZE3LfSREudQfGzqGKsYkEunlnPW7C0jt0vnXipKLq_678OQljM5LNpK3INHGRk74lq_2UnPI2anprfelwNxCrrRN9NtaY6569UtYdD6RuFg8jmgykZbiHLHjyYLrJc0hbx-REd-yrJ9UAbj8xdoywqzwkx3EtkKUk/w640-h328/network-5.png" width="640" /></a></div><p> </p><p>Many of the ethernet-over-power products come in a 2-pack. The two
devices are identical, either one of them can be used as the bridge device or for a leaf device.</p><p></p><p>From what I can tell, ethernet-over-power has no problem "going through" electrical panels, and has no problem connecting devices which are found on either side of the panel. Maybe that's related to the specific panels I have, but I actually have 2 panels involved in my setup, from 2 different manufacturers, and neither panel seems to be an issue.</p><h3 style="text-align: left;">Distance and Length <br /></h3><p>We have a house that is significantly longer in the east-west orientation, and narrower north-south. Since our house is long east-to-west, I decided to try placing the bridge using an outlet that is somewhere around the middle of the house (lengthwise) and then test this setup by placing leaf devices at various points around the house (including at both extreme ends). Unsurprisingly, the devices placed closer to the bridge work fine, but surprisingly devices at the extreme east and west side of the house don't get any connectivity. Length/distance is definitely an issue for this technology. Moving the bridge to different outlets around the middle of the house did change which leaf devices could be reached, but I wasn't able to find one place for the bridge such that all leaf devices could be seen.</p><p>It's important to note that distance is a measure of the length of the
power wires, not the distance between two outlets "as the bird flies".
Just because two outlets might be located relatively close to each other
in a room, doesn't mean they they have a short run of electrical wire between
them. Both of them could be on the same circuit, or they could each be at the end of two separate and long runs.
However, if two outlets are located close to each other in the same room, it's not unreasonable
to assume there isn't much wire between them, but that might not always
be the case. <br /></p><p>House length, hence power wire length, is definitely a factor in whether this technology will work for you. Manufacturers of these devices will often try to put some kind of number on what sort of distances over which they expect their technology to work, but these numbers might as well be pulled from thin air. Several manufacturers claim their devices are good for up to 1000'. My house is only 100' long. And yet placing the bridge in the middle of my house, I could not communicate reliably with devices at both ends (i.e. 50' each way). Therefore, either whoever wired up my house went crazy and used 10x the amount of wire required, or the specs on the ethernet-over-power devices is bogus.</p><p>If the values were just a little off then I could dismiss it as being the difference between theory and practice, or the difference between a lab environment and a setup in the field. But being off by a factor of roughly 10 is getting into "bogus" territory.<br /></p><h3 style="text-align: left;">The Other Factor <br /></h3><p>The second factor took me a little longer to figure out. It was so elusive that I don't even know what it is or what to call it.<br /></p><p>For the past year my hybrid ethernet and ethernet-over-power network was working relatively well. However, perhaps once every 2 weeks or so, I would have these periods where certain leaf nodes would drop off the network, then re-appear again at a later time. Sometimes only the furthest device would be gone, sometimes 2 or 3 devices would be gone, and on rare occasions, all of the devices on the ethernet-over-power network would disappear. Once, for about 4 days in a row, the entire powerline network would
completely disappear at exactly 7pm every day for roughly an hour. Eventually all the network devices would re-appear again and the network continued mostly working. Sometimes they would re-appear after a couple minutes, sometimes it would take several hours.<br /></p><p>Due to the unpredictability of these events, it was hard to understand what was happening. I searched and searched online trying to find answers but nothing definitive came up. After a while I developed a theory that these "brown outs" tended to occur when large loads were running (hot water tanks, ovens, or the cloths dryer) so I started paying attention to those things. Usually those did explain some of the issues, but not entirely. For example: my cloths dryer (a 2-phase, 240V, 30A device) had no effect on the powerline network that I could tell. My dishwasher, however, which is just a regular single-phase 15A system, definitely would cause issues. I'm also pretty sure that my seasonal winter lighting (strings of LEDs) were causing issues too.</p><p>So it seems as though the best way to explain it is to say that some devices will cause issues with the working of a powerline system and others won't. Usually the devices that are a larger load on the electrical system will be the ones that cause issues, but that's not always the case. Sometimes a "regular" device can cause havoc. There's a general correlation between higher load devices causing larger disruptions to the powerline network, but it's not absolutely true in all cases.<br /></p><p>One person I was speaking with suggested that perhaps these issues could be the result of some combination of load, phases, and frequency, or perhaps the <i>dirtiness</i>, of some electronic devices. Another person claimed that some utility companies might be using some form of ethernet-over-power themselves to read power meters for billing purposes.</p><p>I don't know the cause, I only know that for me ethernet-over-power is not entirely reliable and determining the exact causes will need much more investigation. But even if I found exact answers to all my questions, it still wouldn't fix the problem.<br /></p><h3 style="text-align: left;">My Conclusion<br /></h3><p>The conclusion I have reached is that ethernet-over-power is affected primarily by 2 factors: distance, and something else. The something else is hard to define and could be combination of higher loads, or something to do with phases and/or frequencies, or poorly designed electrical devices which cause noise in the power network, or the result of interference by utility companies. The point is, you can't simply make a list of all your electrical devices, then look through the list and know beforehand which ones are going to interfere with the ethernet-over-power network or to what extent (if at all).<br /></p><p>Ethernet-over-power does not work reliably enough for me and will not provide the coverage and 24/7 reliability that I want. I tried it for a year and am removing it in favour of running more ethernet. However, although it doesn't work for me, my co-worker claims it works perfectly for him.</p><p>Hard-wired networking provides the best experience and the most reliable connections. Alternatives to hard-wired networking will probably be cheaper, but less reliable. Will ethernet-over-power work for you? Unfortunately there's no way to know in advance. The only way to know for sure is to spend the money and try it. If it works, great! Otherwise...<br /></p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-32172906327946053632023-01-30T22:37:00.003-05:002023-01-30T22:37:43.477-05:00AllWinner Nezha D1<p>I decided to jump on the Linux-capable RISC-V bandwagon by buying myself the AllWinner Nezha D1. Ever since it arrived, I've spent the last couple evenings working with it to gauge its suitability for inclusion in some projects. Overall my impression has been quite positive!</p><p>I won't bore you here with specs you can easily find elsewhere, but the gist is the Nezha-D1 is a 64-bit, hard-core, RISC-V based board in a roughly RaspberryPi form-factor, with a RaspberryPi-style 40-pin expansion header.</p><h2 style="text-align: left;">Yocto</h2><p style="text-align: left;">My first question with a new board is always: "can I build an image for it with Yocto?" If I can't use Yocto with it, then I'm not interested. In fact, I always do a test build in Yocto before even thinking of buying a board. Of course I can't know if the image will work until I actually get the board, but if that basic step doesn't work, then the board is not worth my time or money. (Unless, of course, I'm somehow thinking that I might take a crack at adding Yocto support for the board)</p><p style="text-align: left;">To see if Yocto support is even a possibility, check: <a href="https://layers.openembedded.org/">https://layers.openembedded.org/</a> . Verify the branch is "master", click on "Machines" and type "nezha" into the search bar: <a href="https://layers.openembedded.org/layerindex/branch/master/machines/?q=nezha&search=1">https://layers.openembedded.org/layerindex/branch/master/machines/?q=nezha&search=1</a> There is a "<span style="font-family: courier;">nezha-allwinner-d1</span>" machine defined in the <a href="https://layers.openembedded.org/layerindex/branch/master/layer/meta-riscv/" target="_blank">meta-riscv</a> layer.</p><p style="text-align: left;">The first thing I do is to download <span style="font-family: courier;">meta-riscv</span>, its dependencies (<span style="font-family: courier;">openembedded-core</span>), as well as <span style="font-family: courier;">bitbake</span>, then perform a <span style="font-family: courier;">nodistro core-image-base</span> build to see if it succeeds. It does, so I proceed to buy the board.</p><h2 style="text-align: left;">Build</h2><p style="text-align: left;">Here are the details of my build.</p>
<h4 style="text-align: left;">conf/local.conf</h4>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">MACHINE</span> = <span style="color: #bf7f0f;">"nezha-allwinner-d1"</span>
<span style="color: #2db5b5;">DISTRO</span> = <span style="color: #bf7f0f;">"nodistro"</span>
<span style="color: #2db5b5;">DL_DIR</span> = <span style="color: #bf7f0f;">"/opt/Downloads"</span>
<span style="color: #2db5b5;">DISTRO_FEATURES</span> = <span style="color: #bf7f0f;">""</span>
<span style="color: #2db5b5;">INHERT</span> += <span style="color: #bf7f0f;">"buildhistory image-buildinfo buildstats-summary"</span>
<span style="color: #2db5b5;">BUILDHISTORY_COMMIT</span> = <span style="color: #bf7f0f;">"1"</span>
<span style="color: #2db5b5;">SSTATE_DIR</span> = <span style="color: #bf7f0f;">"/z/sstate"</span>
<span style="color: #2db5b5;">PACKAGE_CLASSES</span> ?= <span style="color: #bf7f0f;">"package_ipk"</span>
<span style="color: #2db5b5;">EXTRA_IMAGE_FEATURES</span> ?= <span style="color: #bf7f0f;">"debug-tweaks"</span>
<span style="color: #2db5b5;">USER_CLASSES</span> ?= <span style="color: #bf7f0f;">"buildstats"</span>
<span style="color: #2db5b5;">PATCHRESOLVE</span> = <span style="color: #bf7f0f;">"noop"</span>
<span style="color: #2db5b5;">BB_DISKMON_DIRS</span> ??= <span style="color: #bf7f0f;">"\</span>
<span style="color: #bf7f0f;"> STOPTASKS,</span><span style="color: #777777; font-style: italic;">${TMPDIR}</span><span style="color: #bf7f0f;">,1G,100K \</span>
<span style="color: #bf7f0f;"> STOPTASKS,</span><span style="color: #777777; font-style: italic;">${DL_DIR}</span><span style="color: #bf7f0f;">,1G,100K \</span>
<span style="color: #bf7f0f;"> STOPTASKS,</span><span style="color: #777777; font-style: italic;">${SSTATE_DIR}</span><span style="color: #bf7f0f;">,1G,100K \</span>
<span style="color: #bf7f0f;"> STOPTASKS,/tmp,100M,100K \</span>
<span style="color: #bf7f0f;"> HALT,</span><span style="color: #777777; font-style: italic;">${TMPDIR}</span><span style="color: #bf7f0f;">,100M,1K \</span>
<span style="color: #bf7f0f;"> HALT,</span><span style="color: #777777; font-style: italic;">${DL_DIR}</span><span style="color: #bf7f0f;">,100M,1K \</span>
<span style="color: #bf7f0f;"> HALT,</span><span style="color: #777777; font-style: italic;">${SSTATE_DIR}</span><span style="color: #bf7f0f;">,100M,1K \</span>
<span style="color: #bf7f0f;"> HALT,/tmp,10M,1K"</span>
<span style="color: #bf7f0f;">PACKAGECONFIG:append:pn-qemu-system-native</span> <span style="color: #bf7f0f;">=</span> <span style="color: #bf7f0f;">"</span> <span style="color: #bf7f0f;">sdl"</span>
<span style="color: #bf7f0f;">PACKAGECONFIG:append:pn-nativesdk-qemu</span> <span style="color: #bf7f0f;">=</span> <span style="color: #bf7f0f;">"</span> <span style="color: #bf7f0f;">sdl"</span>
<span style="color: #2db5b5;">CONF_VERSION</span> = <span style="color: #bf7f0f;">"2"</span>
</pre></td></tr></tbody></table></div>
<h4 style="text-align: left;">conf/bblayers.conf</h4>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;"># LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf</span>
<span style="color: #777777; font-style: italic;"># changes incompatibly</span>
<span style="color: #2db5b5;">LCONF_VERSION</span> = <span style="color: #bf7f0f;">"7"</span>
<span style="color: #2db5b5;">BBPATH</span> = <span style="color: #bf7f0f;">"</span><span style="color: #777777; font-style: italic;">${TOPDIR}</span><span style="color: #bf7f0f;">"</span>
<span style="color: #2db5b5;">BBFILES</span> ?= <span style="color: #bf7f0f;">""</span>
<span style="color: #2db5b5;">BBLAYERS</span> ?= <span style="color: #bf7f0f;">" \</span>
<span style="color: #bf7f0f;"> /z/build-master/nezha/layers/meta-riscv \</span>
<span style="color: #bf7f0f;"> /z/build-master/nezha/layers/openembedded-core/meta \</span>
<span style="color: #bf7f0f;"> "</span>
</pre></td></tr></tbody></table></div>
<h4 style="text-align: left;">build</h4>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake core-image-base
<span style="color: #777777;">Loading cache: 100% | | ETA: --:--:--</span>
<span style="color: #777777;">Loaded 0 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |################################################################| Time: 0:00:06</span>
<span style="color: #777777;">Parsing of 907 .bb files complete (0 cached, 907 parsed). 1710 targets, 224 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "2.2.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "opensuseleap-15.3"</span>
<span style="color: #777777;">TARGET_SYS = "riscv64-oe-linux"</span>
<span style="color: #777777;">MACHINE = "nezha-allwinner-d1"</span>
<span style="color: #777777;">DISTRO = "nodistro"</span>
<span style="color: #777777;">DISTRO_VERSION = "nodistro.0"</span>
<span style="color: #777777;">TUNE_FEATURES = "riscv64"</span>
<span style="color: #777777;">meta-riscv = "master:d6e3efd54a3c1361fecf2a56c6f4f590fbe676d9"</span>
<span style="color: #777777;">meta = "master:47f6a75960b3af2be7f45fd06e2fb73549b6933b"</span>
<span style="color: #777777;">Initialising tasks: 100% |#############################################################| Time: 0:00:01</span>
<span style="color: #777777;">Sstate summary: Wanted 765 Local 3 Mirrors 0 Missed 762 Current 0 (0% match, 0% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #6d6d00;">WARNING: opensbi-1.1-r0 do_package_qa: QA Issue: File /share/opensbi/lp64/generic/firmware/fw_jump.elf in package opensbi contains reference to TMPDIR</span>
<span style="color: #6d6d00;">File /share/opensbi/lp64/generic/firmware/fw_dynamic.elf in package opensbi contains reference to TMPDIR</span>
<span style="color: #6d6d00;">File /share/opensbi/lp64/generic/firmware/fw_payload.elf in package opensbi contains reference to TMPDIR [buildpaths]</span>
<span style="color: #6d6d00;">WARNING: opensbi-1.1-r0 do_package_qa: QA Issue: File /share/opensbi/lp64/generic/firmware/.debug/fw_jump.elf in package opensbi-dbg contains reference to TMPDIR</span>
<span style="color: #6d6d00;">File /share/opensbi/lp64/generic/firmware/.debug/fw_dynamic.elf in package opensbi-dbg contains reference to TMPDIR</span>
<span style="color: #6d6d00;">File /share/opensbi/lp64/generic/firmware/.debug/fw_payload.elf in package opensbi-dbg contains reference to TMPDIR [buildpaths]</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 2031 tasks of which 3 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">Summary: There were 2 WARNING messages.</span>
</pre></td></tr></tbody></table></div>
<h2 style="text-align: left;"><br /></h2><h2 style="text-align: left;">First Boot</h2><p style="text-align: left;">After the build completes successfully, flash the image to an SDcard. Most BSP layers create an <span style="font-family: courier;"><image>-<machine>.<span>wic</span></span> file (sometimes it's just <span style="font-family: courier;">wic</span> by itself, sometimes it's compressed in one way or another to produce <span style="font-family: courier;">*wic.gz</span>, <span style="font-family: courier;">*wic.bz2</span>, and/or <span style="font-family: courier;">*wic.xz</span>). One of these <span style="font-family: courier;">wic</span> files needs to be flashed with <span style="font-family: courier;">bmaptool</span>. You could download, build, and install <span style="font-family: courier;">bmaptool</span> yourself, or you could get Yocto to do it for you:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake bmap-tools-native -caddto_recipe_sysroot
<span style="color: #777777;">Loading cache: 100% |##################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 1709 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 907 .bb files complete (906 cached, 1 parsed). 1710 targets, 224 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "2.2.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "opensuseleap-15.3"</span>
<span style="color: #777777;">TARGET_SYS = "riscv64-oe-linux"</span>
<span style="color: #777777;">MACHINE = "nezha-allwinner-d1"</span>
<span style="color: #777777;">DISTRO = "nodistro"</span>
<span style="color: #777777;">DISTRO_VERSION = "nodistro.0"</span>
<span style="color: #777777;">TUNE_FEATURES = "riscv64"</span>
<span style="color: #777777;">meta-riscv = "master:d6e3efd54a3c1361fecf2a56c6f4f590fbe676d9"</span>
<span style="color: #777777;">meta = "master:47f6a75960b3af2be7f45fd06e2fb73549b6933b"</span>
<span style="color: #777777;">Initialising tasks: 100% |#############################################################| Time: 0:00:01</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Local 0 Mirrors 0 Missed 0 Current 76 (0% match, 100% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 343 tasks of which 342 didn't need to be rerun and all succeeded.</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Now to invoke your Yocto-built <span style="font-family: courier;">bmaptool</span> use:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> oe-run-native bmap-tools-native bmaptool copy tmp-glibc/deploy/images/nezha-allwinner-d1/core-image-base-nezha-allwinner-d1.wic.gz /dev/sdl
<span style="color: #777777;">Running bitbake -e bmap-tools-native</span>
<span style="color: #777777;">bmaptool: info: discovered bmap file 'tmp-glibc/deploy/images/nezha-allwinner-d1/core-image-base-nezha-allwinner-d1.wic.bmap'</span>
<span style="color: #777777;">bmaptool: info: block map format version 2.0</span>
<span style="color: #777777;">bmaptool: info: 3601408 blocks of size 4096 (13.7 GiB), mapped 21501 blocks (84.0 MiB or 0.6%)</span>
<span style="color: #777777;">bmaptool: info: copying image 'core-image-base-nezha-allwinner-d1.wic.gz' to block device '/dev/sdl' using bmap file 'core-image-base-nezha-allwinner-d1.wic.bmap'</span>
<span style="color: #777777;">bmaptool: WARNING: failed to disable excessive buffering, expect worse system responsiveness (reason: cannot set max. I/O ratio to 1: [Errno 13] Permission denied: '/sys/dev/block/8:176/bdi/max_ratio')</span>
<span style="color: #777777;">bmaptool: info: 100% copied</span>
<span style="color: #777777;">bmaptool: info: synchronizing '/dev/sdl'</span>
<span style="color: #777777;">bmaptool: info: copying time: 38.4s, copying speed 2.2 MiB/sec</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">(make sure to replace <span style="font-family: courier;">/dev/sdl</span> with which ever device your SDcard is using on your specific host machine)</p><p style="text-align: left;">Plugging your newly-flashed SDcard into your Nezha board, connecting a serial cable, opening up a console application on your host, and applying power to the board you'll see:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">U-Boot SPL 2022.10 (Nov 01 2022 - 04:27:57 +0000)</span>
<span style="color: #777777;">sunxi_ram_probe: dram-controller@3102000: probing</span>
<span style="color: #777777;">DRAM only have internal ZQ!!</span>
<span style="color: #777777;">ddr_efuse_type: 0x0 </span>
<span style="color: #777777;">[AUTO DEBUG] two rank and full DQ! </span>
<span style="color: #777777;">ddr_efuse_type: 0x0 </span>
<span style="color: #777777;">[AUTO DEBUG] rank 0 row = 15</span>
<span style="color: #777777;">[AUTO DEBUG] rank 0 bank = 8 </span>
<span style="color: #777777;">[AUTO DEBUG] rank 0 page size = 2 KB</span>
<span style="color: #777777;">[AUTO DEBUG] rank 1 row = 15</span>
<span style="color: #777777;">[AUTO DEBUG] rank 1 bank = 8 </span>
<span style="color: #777777;">[AUTO DEBUG] rank 1 page size = 2 KB</span>
<span style="color: #777777;">rank1 config same as rank0</span>
<span style="color: #777777;">DRAM BOOT DRIVE INFO: V0.24</span>
<span style="color: #777777;">DRAM CLK = 792 MHz </span>
<span style="color: #777777;">DRAM Type = 3 (2:DDR2,3:DDR3)</span>
<span style="color: #777777;">DRAMC ZQ value: 0x7b7bfb</span>
<span style="color: #777777;">DRAM ODT value: 0x42.</span>
<span style="color: #777777;">ddr_efuse_type: 0x0 </span>
<span style="color: #777777;">DRAM SIZE =1024 M</span>
<span style="color: #777777;">DRAM simple test OK. </span>
<span style="color: #777777;">mxstatus=0xc0408000 mhcr=0x00000109 mcor=0x00000003 mhint=0x00004000</span>
<span style="color: #777777;">Trying to boot from MMC1</span>
<span style="color: #777777;">PLL reg = 0xf8216300, freq = 1200000000</span>
<span style="color: #777777;">SPL size = 81920, sector = 160 </span>
<span style="color: #777777;">sunxi_ram_get_info: dram-controller@3102000: getting info</span>
<span style="color: #777777;">OpenSBI v1.1</span>
<span style="color: #777777;"> ____ _____ ____ _____</span>
<span style="color: #777777;"> / __ \ / ____| _ \_ _| </span>
<span style="color: #777777;"> | | | |_ __ ___ _ __ | (___ | |_) || |</span>
<span style="color: #777777;"> | | | | '_ \ / _ \ '_ \ \___ \| _ < | | </span>
<span style="color: #777777;"> | |__| | |_) | __/ | | |____) | |_) || |_</span>
<span style="color: #777777;"> \____/| .__/ \___|_| |_|_____/|____/_____|</span>
<span style="color: #777777;"> | | </span>
<span style="color: #777777;"> |_|</span>
<span style="color: #777777;">Platform Name : Allwinner D1 Nezha</span>
<span style="color: #777777;">Platform Features : medeleg</span>
<span style="color: #777777;">Platform HART Count : 1</span>
<span style="color: #777777;">Platform IPI Device : --- </span>
<span style="color: #777777;">Platform Timer Device : --- @ 0Hz </span>
<span style="color: #777777;">Platform Console Device : uart8250</span>
<span style="color: #777777;">Platform HSM Device : sun20i-d1-ppu</span>
<span style="color: #777777;">Platform Reboot Device : sunxi-wdt-reset</span>
<span style="color: #777777;">Platform Shutdown Device : --- </span>
<span style="color: #777777;">Firmware Base : 0x80000000</span>
<span style="color: #777777;">Firmware Size : 276 KB</span>
<span style="color: #777777;">Runtime SBI Version : 1.0 </span>
<span style="color: #777777;">Domain0 Name : root</span>
<span style="color: #777777;">Domain0 Boot HART : 0</span>
<span style="color: #777777;">Domain0 HARTs : 0*</span>
<span style="color: #777777;">Domain0 Region00 : 0x0000000080000000-0x000000008007ffff ()</span>
<span style="color: #777777;">Domain0 Region01 : 0x0000000000000000-0xffffffffffffffff (R,W,X)</span>
<span style="color: #777777;">Domain0 Next Address : 0x0000000042e00000</span>
<span style="color: #777777;">Domain0 Next Arg1 : 0x0000000042e8b7f8</span>
<span style="color: #777777;">Domain0 Next Mode : S-mode</span>
<span style="color: #777777;">Domain0 SysReset : yes </span>
<span style="color: #777777;">Boot HART ID : 0</span>
<span style="color: #777777;">Boot HART Domain : root</span>
<span style="color: #777777;">Boot HART Priv Version : v1.11</span>
<span style="color: #777777;">Boot HART Base ISA : rv64imafdcvx</span>
<span style="color: #777777;">Boot HART ISA Extensions : time</span>
<span style="color: #777777;">Boot HART PMP Count : 8 </span>
<span style="color: #777777;">Boot HART PMP Granularity : 2048</span>
<span style="color: #777777;">Boot HART PMP Address Bits: 38</span>
<span style="color: #777777;">Boot HART MHPM Count : 0 </span>
<span style="color: #777777;">Boot HART MIDELEG : 0x0000000000000222</span>
<span style="color: #777777;">Boot HART MEDELEG : 0x000000000000b109</span>
<span style="color: #777777;">sunxi_set_gate: (CLK#24) unhandled</span>
<span style="color: #777777;">U-Boot 2022.10 (Nov 01 2022 - 04:27:57 +0000) Allwinner Technology</span>
<span style="color: #777777;">DRAM: 1 GiB</span>
<span style="color: #777777;">sunxi_set_gate: (CLK#24) unhandled</span>
<span style="color: #777777;">Core: 54 devices, 20 uclasses, devicetree: separate</span>
<span style="color: #777777;">WDT: Started watchdog@6011000 with servicing every 1000ms (16s timeout)</span>
<span style="color: #777777;">MMC: mmc@4020000: 0, mmc@4021000: 1</span>
<span style="color: #777777;">Loading Environment from FAT... PLL reg = 0xf8216300, freq = 1200000000</span>
<span style="color: #777777;">Unable to read "uboot.env" from mmc0:1...</span>
<span style="color: #777777;">In: serial@2500000</span>
<span style="color: #777777;">Out: serial@2500000</span>
<span style="color: #777777;">Err: serial@2500000</span>
<span style="color: #777777;">Net:</span>
<span style="color: #777777;">Warning: ethernet@4500000 (eth0) using random MAC address - c6:3e:31:4e:f8:ec</span>
<span style="color: #777777;">eth0: ethernet@4500000</span>
<span style="color: #777777;">starting USB...</span>
<span style="color: #777777;">Bus usb@4101000: USB EHCI 1.00</span>
<span style="color: #777777;">Bus usb@4101400: USB OHCI 1.0</span>
<span style="color: #777777;">Bus usb@4200000: USB EHCI 1.00</span>
<span style="color: #777777;">Bus usb@4200400: USB OHCI 1.0</span>
<span style="color: #777777;">scanning bus usb@4101000 for devices... 1 USB Device(s) found</span>
<span style="color: #777777;">scanning bus usb@4101400 for devices... 1 USB Device(s) found</span>
<span style="color: #777777;">scanning bus usb@4200000 for devices... 1 USB Device(s) found</span>
<span style="color: #777777;">scanning bus usb@4200400 for devices... 1 USB Device(s) found</span>
<span style="color: #777777;"> scanning usb for storage devices... 0 Storage Device(s) found</span>
<span style="color: #777777;">Hit any key to stop autoboot: 2 ^H^H^H 1 ^H^H^H 0</span>
<span style="color: #777777;">PLL reg = 0xf8216300, freq = 1200000000</span>
<span style="color: #777777;">switch to partitions #0, OK</span>
<span style="color: #777777;">mmc0 is current device</span>
<span style="color: #777777;">Scanning mmc 0:1...</span>
<span style="color: #777777;">Found U-Boot script /boot.scr.uimg</span>
<span style="color: #777777;">1249 bytes read in 1 ms (1.2 MiB/s)</span>
<span style="color: #777777;">## Executing script at 41900000</span>
<span style="color: #777777;">ethernet@4500000 Waiting for PHY auto negotiation to complete......... TIMEOUT !</span>
<span style="color: #777777;">ethernet@4500000 Waiting for PHY auto negotiation to complete......... TIMEOUT !</span>
<span style="color: #777777;">ethernet@4500000 Waiting for PHY auto negotiation to complete......... TIMEOUT !</span>
<span style="color: #777777;">322 bytes read in 1 ms (314.5 KiB/s)</span>
<span style="color: #777777;">5431248 bytes read in 898 ms (5.8 MiB/s)</span>
<span style="color: #777777;">## Loading kernel from FIT Image at 41c00000 ...</span>
<span style="color: #777777;"> Using 'conf-1' configuration</span>
<span style="color: #777777;"> Trying 'kernel-1' kernel subimage</span>
<span style="color: #777777;"> Description: Linux kernel</span>
<span style="color: #777777;"> Type: Kernel Image</span>
<span style="color: #777777;"> Compression: gzip compressed</span>
<span style="color: #777777;"> Data Start: 0x41c0010c</span>
<span style="color: #777777;"> Data Size: 5428090 Bytes = 5.2 MiB</span>
<span style="color: #777777;"> Architecture: RISC-V</span>
<span style="color: #777777;"> OS: Linux</span>
<span style="color: #777777;"> Load Address: 0x40200000</span>
<span style="color: #777777;"> Entry Point: 0x40200000</span>
<span style="color: #777777;"> Hash algo: sha256</span>
<span style="color: #777777;"> Hash value: c0897b7ecc8c79a67ffd0b71af8a90e3bdeb028c9953a13a8a4b2c0dab4e3797</span>
<span style="color: #777777;"> Verifying Hash Integrity ... sha256+ OK</span>
<span style="color: #777777;">## Flattened Device Tree blob at 7fd3e180</span>
<span style="color: #777777;"> Booting using the fdt blob at 0x7fd3e180</span>
<span style="color: #777777;">Working FDT set to 7fd3e180</span>
<span style="color: #777777;"> Uncompressing Kernel Image</span>
<span style="color: #777777;"> Loading Device Tree to 0000000042df2000, end 0000000042dffc27 ... OK</span>
<span style="color: #777777;">Working FDT set to 42df2000</span>
<span style="color: #777777;">Starting kernel ...</span>
<span style="color: #777777;">[ 0.000000] Linux version 6.1.0-rc3-nezha (oe-user@oe-host) (riscv64-oe-linux-gcc (GCC) 12.2.0, GNU ld (GNU Binutils) 2.39.0.20220819) #1 PREEMPT Thu Nov 3 04:49:55 UTC 2022</span>
<span style="color: #777777;">[ 0.000000] OF: fdt: Ignoring memory range 0x40000000 - 0x40200000</span>
<span style="color: #777777;">[ 0.000000] Machine model: Allwinner D1 Nezha</span>
<span style="color: #777777;">[ 0.000000] efi: UEFI not found.</span>
<span style="color: #777777;">[ 0.000000] Zone ranges:</span>
<span style="color: #777777;">[ 0.000000] DMA32 [mem 0x0000000040200000-0x000000007fffffff]</span>
<span style="color: #777777;">[ 0.000000] Normal empty</span>
<span style="color: #777777;">[ 0.000000] Movable zone start for each node</span>
<span style="color: #777777;">[ 0.000000] Early memory node ranges</span>
<span style="color: #777777;">[ 0.000000] node 0: [mem 0x0000000040200000-0x000000007fffffff]</span>
<span style="color: #777777;">[ 0.000000] Initmem setup node 0 [mem 0x0000000040200000-0x000000007fffffff]</span>
<span style="color: #777777;">[ 0.000000] SBI specification v1.0 detected</span>
<span style="color: #777777;">[ 0.000000] SBI implementation ID=0x1 Version=0x10001</span>
<span style="color: #777777;">[ 0.000000] SBI TIME extension detected</span>
<span style="color: #777777;">[ 0.000000] SBI IPI extension detected</span>
<span style="color: #777777;">[ 0.000000] SBI RFENCE extension detected</span>
<span style="color: #777777;">[ 0.000000] SBI SRST extension detected</span>
<span style="color: #777777;">[ 0.000000] riscv: base ISA extensions acdfim</span>
<span style="color: #777777;">[ 0.000000] riscv: ELF capabilities acdfim</span>
<span style="color: #777777;">[ 0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768</span>
<span style="color: #777777;">[ 0.000000] pcpu-alloc: [0] 0</span>
<span style="color: #777777;">[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 257544</span>
<span style="color: #777777;">[ 0.000000] Kernel command line: earlycon=sbi clk_ignore_unused initcall_debug=0 console=ttyS0,115200 loglevel=8 root=/dev/mmcblk0p2 rootwait init=/sbin/init</span>
<span style="color: #777777;">[ 0.000000] Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes, linear)</span>
<span style="color: #777777;">[ 0.000000] Inode-cache hash table entries: 65536 (order: 7, 524288 bytes, linear)</span>
<span style="color: #777777;">[ 0.000000] mem auto-init: stack:all(zero), heap alloc:off, heap free:off</span>
<span style="color: #777777;">[ 0.000000] Memory: 1009936K/1046528K available (6082K kernel code, 4935K rwdata, 4096K rodata, 2127K init, 309K bss, 36592K reserved, 0K cma-reserved)</span>
<span style="color: #777777;">[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1</span>
<span style="color: #777777;">[ 0.000000] rcu: Preemptible hierarchical RCU implementation.</span>
<span style="color: #777777;">[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.</span>
<span style="color: #777777;">[ 0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0</span>
<span style="color: #777777;">[ 0.000000] riscv-intc: 64 local interrupts mapped</span>
<span style="color: #777777;">[ 0.000000] plic: interrupt-controller@10000000: mapped 176 interrupts with 1 handlers for 2 contexts.</span>
<span style="color: #777777;">[ 0.000000] rcu: srcu_init: Setting srcu_struct sizes based on contention.</span>
<span style="color: #777777;">[ 0.000000] riscv-timer: riscv_timer_init_dt: Registering clocksource cpuid [0] hartid [0]</span>
<span style="color: #777777;">[ 0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns</span>
<span style="color: #777777;">[ 0.000001] sched_clock: 64 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns</span>
<span style="color: #777777;">[ 0.000518] clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns</span>
<span style="color: #777777;">[ 0.001450] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=96000)</span>
<span style="color: #777777;">[ 0.001488] pid_max: default: 32768 minimum: 301</span>
<span style="color: #777777;">[ 0.001857] LSM: Security Framework initializing</span>
<span style="color: #777777;">[ 0.002127] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes, linear)</span>
<span style="color: #777777;">[ 0.002175] Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes, linear)</span>
<span style="color: #777777;">[ 0.006058] riscv: ELF compat mode unsupported</span>
<span style="color: #777777;">[ 0.006135] ASID allocator using 16 bits (65536 entries)</span>
<span style="color: #777777;">[ 0.006425] rcu: Hierarchical SRCU implementation.</span>
<span style="color: #777777;">[ 0.006439] rcu: Max phase no-delay instances is 1000.</span>
<span style="color: #777777;">[ 0.006686] EFI services will not be available.</span>
<span style="color: #777777;">[ 0.007641] devtmpfs: initialized</span>
<span style="color: #777777;">[ 0.031148] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns</span>
<span style="color: #777777;">[ 0.031195] futex hash table entries: 256 (order: 0, 6144 bytes, linear)</span>
<span style="color: #777777;">[ 0.031431] pinctrl core: initialized pinctrl subsystem</span>
<span style="color: #777777;">[ 0.034816] NET: Registered PF_NETLINK/PF_ROUTE protocol family</span>
<span style="color: #777777;">[ 0.035494] DMA: preallocated 128 KiB GFP_KERNEL pool for atomic allocations</span>
<span style="color: #777777;">[ 0.035588] DMA: preallocated 128 KiB GFP_KERNEL|GFP_DMA32 pool for atomic allocations</span>
<span style="color: #777777;">[ 0.036553] thermal_sys: Registered thermal governor 'bang_bang'</span>
<span style="color: #777777;">[ 0.036664] thermal_sys: Registered thermal governor 'step_wise'</span>
<span style="color: #777777;">[ 0.036681] thermal_sys: Registered thermal governor 'user_space'</span>
<span style="color: #777777;">[ 0.073318] platform 5460000.tcon-top: Fixing up cyclic dependency with 5200000.mixer</span>
<span style="color: #777777;">[ 0.073562] platform 5460000.tcon-top: Fixing up cyclic dependency with 5100000.mixer</span>
<span style="color: #777777;">[ 0.074743] platform 5461000.lcd-controller: Fixing up cyclic dependency with 5460000.tcon-top</span>
<span style="color: #777777;">[ 0.076089] platform 5470000.lcd-controller: Fixing up cyclic dependency with 5460000.tcon-top</span>
<span style="color: #777777;">[ 0.077337] platform 5500000.hdmi: Fixing up cyclic dependency with 5460000.tcon-top</span>
<span style="color: #777777;">[ 0.081586] platform 7090000.rtc: Fixing up cyclic dependency with 7010000.clock-controller</span>
<span style="color: #777777;">[ 0.085046] platform connector: Fixing up cyclic dependency with 5500000.hdmi</span>
<span style="color: #777777;">[ 0.180753] raid6: int64x8 gen() 156 MB/s</span>
<span style="color: #777777;">[ 0.248633] raid6: int64x4 gen() 198 MB/s</span>
<span style="color: #777777;">[ 0.316715] raid6: int64x2 gen() 180 MB/s</span>
<span style="color: #777777;">[ 0.384610] raid6: int64x1 gen() 161 MB/s</span>
<span style="color: #777777;">[ 0.384629] raid6: using algorithm int64x4 gen() 198 MB/s</span>
<span style="color: #777777;">[ 0.452592] raid6: .... xor() 123 MB/s, rmw enabled</span>
<span style="color: #777777;">[ 0.452607] raid6: using intx1 recovery algorithm</span>
<span style="color: #777777;">[ 0.455199] iommu: Default domain type: Translated</span>
<span style="color: #777777;">[ 0.455218] iommu: DMA domain TLB invalidation policy: strict mode</span>
<span style="color: #777777;">[ 0.456083] SCSI subsystem initialized</span>
<span style="color: #777777;">[ 0.456737] usbcore: registered new interface driver usbfs</span>
<span style="color: #777777;">[ 0.456861] usbcore: registered new interface driver hub</span>
<span style="color: #777777;">[ 0.456981] usbcore: registered new device driver usb</span>
<span style="color: #777777;">[ 0.458805] Advanced Linux Sound Architecture Driver Initialized.</span>
<span style="color: #777777;">[ 0.460733] clocksource: Switched to clocksource timer</span>
<span style="color: #777777;">[ 0.465108] NET: Registered PF_INET protocol family</span>
<span style="color: #777777;">[ 0.465711] IP idents hash table entries: 16384 (order: 5, 131072 bytes, linear)</span>
<span style="color: #777777;">[ 0.473890] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes, linear)</span>
<span style="color: #777777;">[ 0.473950] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)</span>
<span style="color: #777777;">[ 0.474007] TCP established hash table entries: 8192 (order: 4, 65536 bytes, linear)</span>
<span style="color: #777777;">[ 0.474262] TCP bind hash table entries: 8192 (order: 5, 131072 bytes, linear)</span>
<span style="color: #777777;">[ 0.474969] TCP: Hash tables configured (established 8192 bind 8192)</span>
<span style="color: #777777;">[ 0.475212] UDP hash table entries: 512 (order: 2, 16384 bytes, linear)</span>
<span style="color: #777777;">[ 0.475322] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes, linear)</span>
<span style="color: #777777;">[ 0.475767] NET: Registered PF_UNIX/PF_LOCAL protocol family</span>
<span style="color: #777777;">[ 0.477573] workingset: timestamp_bits=46 max_order=18 bucket_order=0</span>
<span style="color: #777777;">[ 0.645753] NET: Registered PF_ALG protocol family</span>
<span style="color: #777777;">[ 0.645796] xor: measuring software checksum speed</span>
<span style="color: #777777;">[ 0.659632] 8regs : 712 MB/sec</span>
<span style="color: #777777;">[ 0.673527] 8regs_prefetch : 710 MB/sec</span>
<span style="color: #777777;">[ 0.687386] 32regs : 711 MB/sec</span>
<span style="color: #777777;">[ 0.701289] 32regs_prefetch : 709 MB/sec</span>
<span style="color: #777777;">[ 0.701306] xor: using function: 8regs (712 MB/sec)</span>
<span style="color: #777777;">[ 0.701326] async_tx: api initialized (async)</span>
<span style="color: #777777;">[ 0.743397] Serial: 8250/16550 driver, 6 ports, IRQ sharing disabled</span>
<span style="color: #777777;">[ 0.761274] sun8i-mixer 5100000.mixer: Adding to iommu group 0</span>
<span style="color: #777777;">[ 0.762086] sun8i-mixer 5200000.mixer: Adding to iommu group 0</span>
<span style="color: #777777;">[ 0.772085] PPP generic driver version 2.4.2</span>
<span style="color: #777777;">[ 0.772522] PPP BSD Compression module registered</span>
<span style="color: #777777;">[ 0.772541] PPP Deflate Compression module registered</span>
<span style="color: #777777;">[ 0.772553] NET: Registered PF_PPPOX protocol family</span>
<span style="color: #777777;">[ 0.772610] SLIP: version 0.8.4-NET3.019-NEWTTY (dynamic channels, max=256) (6 bit encapsulation enabled).</span>
<span style="color: #777777;">[ 0.772629] CSLIP: code copyright 1989 Regents of the University of California.</span>
<span style="color: #777777;">[ 0.772638] SLIP linefill/keepalive option.</span>
<span style="color: #777777;">[ 0.774534] usbcore: registered new interface driver uas</span>
<span style="color: #777777;">[ 0.774650] usbcore: registered new interface driver usb-storage</span>
<span style="color: #777777;">[ 0.774924] usbcore: registered new interface driver ch341</span>
<span style="color: #777777;">[ 0.775004] usbserial: USB Serial support registered for ch341-uart</span>
<span style="color: #777777;">[ 0.776114] UDC core: g_ether: couldn't find an available UDC</span>
<span style="color: #777777;">[ 0.776714] i2c_dev: i2c /dev entries driver</span>
<span style="color: #777777;">[ 0.779899] softdog: initialized. soft_noboot=0 soft_margin=60 sec soft_panic=0 (nowayout=0)</span>
<span style="color: #777777;">[ 0.779926] softdog: soft_reboot_cmd=<not set> soft_active_on_boot=0</span>
<span style="color: #777777;">[ 0.781409] device-mapper: ioctl: 4.47.0-ioctl (2022-07-28) initialised: dm-devel@redhat.com</span>
<span style="color: #777777;">[ 0.784439] ledtrig-cpu: registered to indicate activity on CPUs</span>
<span style="color: #777777;">[ 0.788196] usbcore: registered new interface driver snd-usb-audio</span>
<span style="color: #777777;">[ 0.791267] pktgen: Packet Generator for packet performance testing. Version: 2.75</span>
<span style="color: #777777;">[ 0.792034] ipip: IPv4 and MPLS over IPv4 tunneling driver</span>
<span style="color: #777777;">[ 0.793522] gre: GRE over IPv4 demultiplexor driver</span>
<span style="color: #777777;">[ 0.793541] ip_gre: GRE over IPv4 tunneling driver</span>
<span style="color: #777777;">[ 0.799291] NET: Registered PF_INET6 protocol family</span>
<span style="color: #777777;">[ 0.804235] Segment Routing with IPv6</span>
<span style="color: #777777;">[ 0.804438] In-situ OAM (IOAM) with IPv6</span>
<span style="color: #777777;">[ 0.804669] NET: Registered PF_PACKET protocol family</span>
<span style="color: #777777;">[ 0.804710] NET: Registered PF_KEY protocol family</span>
<span style="color: #777777;">[ 0.805062] 8021q: 802.1Q VLAN Support v1.8</span>
<span style="color: #777777;">[ 0.805652] sctp: Hash tables configured (bind 512/512)</span>
<span style="color: #777777;">[ 0.806479] tipc: Activated (version 2.0.0)</span>
<span style="color: #777777;">[ 0.807089] NET: Registered PF_TIPC protocol family</span>
<span style="color: #777777;">[ 0.807429] tipc: Started in single node mode</span>
<span style="color: #777777;">[ 0.808374] Key type .fscrypt registered</span>
<span style="color: #777777;">[ 0.808395] Key type fscrypt-provisioning registered</span>
<span style="color: #777777;">[ 0.810354] Key type encrypted registered</span>
<span style="color: #777777;">[ 0.863941] sun4i-drm display-engine: Adding to iommu group 0</span>
<span style="color: #777777;">[ 0.878031] sun4i-drm display-engine: bound 5100000.mixer (ops 0xffffffff80b01458)</span>
<span style="color: #777777;">[ 0.883298] sun4i-drm display-engine: bound 5200000.mixer (ops 0xffffffff80b01458)</span>
<span style="color: #777777;">[ 0.883345] sun4i-drm display-engine: bound 5460000.tcon-top (ops 0xffffffff80b057d8)</span>
<span style="color: #777777;">[ 0.884578] sun4i-drm display-engine: No panel or bridge found... RGB output disabled</span>
<span style="color: #777777;">[ 0.884614] sun4i-drm display-engine: bound 5461000.lcd-controller (ops 0xffffffff80afe3c0)</span>
<span style="color: #777777;">[ 0.885415] sun4i-drm display-engine: bound 5470000.lcd-controller (ops 0xffffffff80afe3c0)</span>
<span style="color: #777777;">[ 0.886388] sun8i-dw-hdmi 5500000.hdmi: Detected HDMI TX controller v2.12a with HDCP (sun8i_dw_hdmi_phy)</span>
<span style="color: #777777;">[ 0.887499] sun8i-dw-hdmi 5500000.hdmi: registered DesignWare HDMI I2C bus driver</span>
<span style="color: #777777;">[ 0.888126] sun4i-drm display-engine: bound 5500000.hdmi (ops 0xffffffff80b00528)</span>
<span style="color: #777777;">[ 0.889925] [drm] Initialized sun4i-drm 1.0.0 20150629 for display-engine on minor 0</span>
<span style="color: #777777;">[ 0.900271] input: 2009800.keys as /devices/platform/soc/2009800.keys/input/input0</span>
<span style="color: #777777;">[ 0.918653] sunxi-wdt 6011000.watchdog: Watchdog enabled (timeout=16 sec, nowayout=0)</span>
<span style="color: #777777;">[ 0.964473] sun20i-d1-pinctrl 2000000.pinctrl: initialized sunXi PIO driver</span>
<span style="color: #777777;">[ 0.968642] printk: console [ttyS0] disabled</span>
<span style="color: #777777;">[ 0.989174] 2500000.serial: ttyS0 at MMIO 0x2500000 (irq = 209, base_baud = 1500000) is a 16550A</span>
<span style="color: #777777;">[ 1.931142] printk: console [ttyS0] enabled</span>
<span style="color: #777777;">[ 1.958274] 2500400.serial: ttyS1 at MMIO 0x2500400 (irq = 210, base_baud = 1500000) is a 16550A</span>
<span style="color: #777777;">[ 1.971932] spi-nand spi0.0: Macronix SPI NAND was found.</span>
<span style="color: #777777;">[ 1.977447] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 64</span>
<span style="color: #777777;">[ 1.989585] 4 fixed-partitions partitions found on MTD device spi0.0</span>
<span style="color: #777777;">[ 1.996036] Creating 4 MTD partitions on "spi0.0":</span>
<span style="color: #777777;">[ 2.000888] 0x000000000000-0x000000100000 : "boot0"</span>
<span style="color: #777777;">[ 2.012150] 0x000000100000-0x000000400000 : "uboot"</span>
<span style="color: #777777;">[ 2.030040] 0x000000400000-0x000000500000 : "secure_storage"</span>
<span style="color: #777777;">[ 2.042181] 0x000000500000-0x000010000000 : "sys"</span>
<span style="color: #777777;">[ 2.756834] random: crng init done</span>
<span style="color: #777777;">[ 2.848410] dwmac-sun8i 4500000.ethernet: IRQ eth_wake_irq not found</span>
<span style="color: #777777;">[ 2.854891] dwmac-sun8i 4500000.ethernet: IRQ eth_lpi not found</span>
<span style="color: #777777;">[ 2.861560] dwmac-sun8i 4500000.ethernet: PTP uses main clock</span>
<span style="color: #777777;">[ 2.867444] dwmac-sun8i 4500000.ethernet: Current syscon value is not the default 50006 (expect 0)</span>
<span style="color: #777777;">[ 2.876892] dwmac-sun8i 4500000.ethernet: No HW DMA feature register supported</span>
<span style="color: #777777;">[ 2.884221] dwmac-sun8i 4500000.ethernet: RX Checksum Offload Engine supported</span>
<span style="color: #777777;">[ 2.891498] dwmac-sun8i 4500000.ethernet: COE Type 2</span>
<span style="color: #777777;">[ 2.896565] dwmac-sun8i 4500000.ethernet: TX Checksum insertion supported</span>
<span style="color: #777777;">[ 2.903466] dwmac-sun8i 4500000.ethernet: Normal descriptors</span>
<span style="color: #777777;">[ 2.909191] dwmac-sun8i 4500000.ethernet: Chain mode enabled</span>
<span style="color: #777777;">[ 2.931798] pcf857x 1-0038: probed</span>
<span style="color: #777777;">[ 2.945141] sunxi-mmc 4020000.mmc: Got CD GPIO</span>
<span style="color: #777777;">[ 2.952323] sunxi-mmc 4021000.mmc: allocated mmc-pwrseq</span>
<span style="color: #777777;">[ 2.962105] phy phy-4100400.phy.1: Changing dr_mode to 1</span>
<span style="color: #777777;">[ 2.970229] ehci-platform 4200000.usb: EHCI Host Controller</span>
<span style="color: #777777;">[ 2.977197] usb_phy_generic usb_phy_generic.2.auto: dummy supplies not allowed for exclusive requests</span>
<span style="color: #777777;">[ 2.988506] sunxi-mmc 4020000.mmc: initialized, max. request size: 2047 KB, uses new timings mode</span>
<span style="color: #777777;">[ 2.997607] sunxi-mmc 4021000.mmc: initialized, max. request size: 2047 KB, uses new timings mode</span>
<span style="color: #777777;">[ 3.008127] ohci-platform 4200400.usb: Generic Platform OHCI controller</span>
<span style="color: #777777;">[ 3.015225] ehci-platform 4200000.usb: new USB bus registered, assigned bus number 1</span>
<span style="color: #777777;">[ 3.023483] ohci-platform 4200400.usb: new USB bus registered, assigned bus number 2</span>
<span style="color: #777777;">[ 3.032571] ehci-platform 4200000.usb: irq 218, io mem 0x04200000</span>
<span style="color: #777777;">[ 3.039264] ohci-platform 4200400.usb: irq 220, io mem 0x04200400</span>
<span style="color: #777777;">[ 3.060790] ehci-platform 4200000.usb: USB 2.0 started, EHCI 1.00</span>
<span style="color: #777777;">[ 3.067393] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.01</span>
<span style="color: #777777;">[ 3.075819] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1</span>
<span style="color: #777777;">[ 3.083176] usb usb1: Product: EHCI Host Controller</span>
<span style="color: #777777;">[ 3.088179] usb usb1: Manufacturer: Linux 6.1.0-rc3-nezha ehci_hcd</span>
<span style="color: #777777;">[ 3.096054] mmc1: new high speed SDIO card at address 0001</span>
<span style="color: #777777;">[ 3.101710] usb usb1: SerialNumber: 4200000.usb</span>
<span style="color: #777777;">[ 3.112043] hub 1-0:1.0: USB hub found</span>
<span style="color: #777777;">[ 3.116060] hub 1-0:1.0: 1 port detected</span>
<span style="color: #777777;">[ 3.121446] usb usb2: New USB device found, idVendor=1d6b, idProduct=0001, bcdDevice= 6.01</span>
<span style="color: #777777;">[ 3.130095] mmc0: new high speed SDXC card at address 1234</span>
<span style="color: #777777;">[ 3.137528] mmcblk0: mmc0:1234 SA64G 58.0 GiB</span>
<span style="color: #777777;">[ 3.142114] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1</span>
<span style="color: #777777;">[ 3.151442] usb usb2: Product: Generic Platform OHCI controller</span>
<span style="color: #777777;">[ 3.157643] mmcblk0: p1 p2</span>
<span style="color: #777777;">[ 3.160888] usb usb2: Manufacturer: Linux 6.1.0-rc3-nezha ohci_hcd</span>
<span style="color: #777777;">[ 3.167947] usb usb2: SerialNumber: 4200400.usb</span>
<span style="color: #777777;">[ 3.173925] hub 2-0:1.0: USB hub found</span>
<span style="color: #777777;">[ 3.177879] hub 2-0:1.0: 1 port detected</span>
<span style="color: #777777;">[ 4.033013] ohci-platform 4101400.usb: Generic Platform OHCI controller</span>
<span style="color: #777777;">[ 4.039773] ehci-platform 4101000.usb: EHCI Host Controller</span>
<span style="color: #777777;">[ 4.045549] musb-hdrc musb-hdrc.3.auto: MUSB HDRC host driver</span>
<span style="color: #777777;">[ 4.051523] ehci-platform 4101000.usb: new USB bus registered, assigned bus number 3</span>
<span style="color: #777777;">[ 4.059408] musb-hdrc musb-hdrc.3.auto: new USB bus registered, assigned bus number 4</span>
<span style="color: #777777;">[ 4.067363] ohci-platform 4101400.usb: new USB bus registered, assigned bus number 5</span>
<span style="color: #777777;">[ 4.075511] ehci-platform 4101000.usb: irq 217, io mem 0x04101000</span>
<span style="color: #777777;">[ 4.082107] usb usb4: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.01</span>
<span style="color: #777777;">[ 4.090707] ohci-platform 4101400.usb: irq 219, io mem 0x04101400</span>
<span style="color: #777777;">[ 4.096982] usb usb4: New USB device strings: Mfr=3, Product=2, SerialNumber=1</span>
<span style="color: #777777;">[ 4.104278] usb usb4: Product: MUSB HDRC host driver</span>
<span style="color: #777777;">[ 4.109297] usb usb4: Manufacturer: Linux 6.1.0-rc3-nezha musb-hcd</span>
<span style="color: #777777;">[ 4.115550] ehci-platform 4101000.usb: USB 2.0 started, EHCI 1.00</span>
<span style="color: #777777;">[ 4.121720] usb usb4: SerialNumber: musb-hdrc.3.auto</span>
<span style="color: #777777;">[ 4.128124] hub 4-0:1.0: USB hub found</span>
<span style="color: #777777;">[ 4.132081] hub 4-0:1.0: 1 port detected</span>
<span style="color: #777777;">[ 4.137396] usb usb3: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.01</span>
<span style="color: #777777;">[ 4.146375] using random self ethernet address</span>
<span style="color: #777777;">[ 4.151051] using random host ethernet address</span>
<span style="color: #777777;">[ 4.155661] usb usb3: New USB device strings: Mfr=3, Product=2, SerialNumber=1</span>
<span style="color: #777777;">[ 4.168635] usb0: HOST MAC 0a:2e:24:ef:46:b5</span>
<span style="color: #777777;">[ 4.173025] usb usb3: Product: EHCI Host Controller</span>
<span style="color: #777777;">[ 4.177963] usb0: MAC 06:24:1a:84:1b:76</span>
<span style="color: #777777;">[ 4.181861] usb usb3: Manufacturer: Linux 6.1.0-rc3-nezha ehci_hcd</span>
<span style="color: #777777;">[ 4.188147] g_ether gadget.0: Ethernet Gadget, version: Memorial Day 2008</span>
<span style="color: #777777;">[ 4.195031] usb usb3: SerialNumber: 4101000.usb</span>
<span style="color: #777777;">[ 4.199631] g_ether gadget.0: g_ether ready</span>
<span style="color: #777777;">[ 4.205342] hub 3-0:1.0: USB hub found</span>
<span style="color: #777777;">[ 4.211519] clk: Not disabling unused clocks</span>
<span style="color: #777777;">[ 4.216004] hub 3-0:1.0: 1 port detected</span>
<span style="color: #777777;">[ 4.220024] ALSA device list:</span>
<span style="color: #777777;">[ 4.223052] #0: sun20i-codec</span>
<span style="color: #777777;">[ 4.227536] usb usb5: New USB device found, idVendor=1d6b, idProduct=0001, bcdDevice= 6.01</span>
<span style="color: #777777;">[ 4.236543] usb usb5: New USB device strings: Mfr=3, Product=2, SerialNumber=1</span>
<span style="color: #777777;">[ 4.243902] usb usb5: Product: Generic Platform OHCI controller</span>
<span style="color: #777777;">[ 4.250050] usb usb5: Manufacturer: Linux 6.1.0-rc3-nezha ohci_hcd</span>
<span style="color: #777777;">[ 4.256313] usb usb5: SerialNumber: 4101400.usb</span>
<span style="color: #777777;">[ 4.262237] hub 5-0:1.0: USB hub found</span>
<span style="color: #777777;">[ 4.266193] hub 5-0:1.0: 1 port detected</span>
<span style="color: #777777;">[ 4.271278] md: Waiting for all devices to be available before autodetect</span>
<span style="color: #777777;">[ 4.278298] md: If you don't use raid, use raid=noautodetect</span>
<span style="color: #777777;">[ 4.284029] md: Autodetecting RAID arrays.</span>
<span style="color: #777777;">[ 4.288170] md: autorun ...</span>
<span style="color: #777777;">[ 4.291006] md: ... autorun DONE.</span>
<span style="color: #777777;">[ 4.322157] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Quota mode: disabled.</span>
<span style="color: #777777;">[ 4.331208] VFS: Mounted root (ext4 filesystem) readonly on device 179:2.</span>
<span style="color: #777777;">[ 4.339657] devtmpfs: mounted</span>
<span style="color: #777777;">[ 4.345575] Freeing unused kernel image (initmem) memory: 2124K</span>
<span style="color: #777777;">[ 4.351621] Run /sbin/init as init process</span>
<span style="color: #777777;">[ 4.355805] with arguments:</span>
<span style="color: #777777;">[ 4.358815] /sbin/init</span>
<span style="color: #777777;">[ 4.361565] with environment:</span>
<span style="color: #777777;">[ 4.364716] HOME=/</span>
<span style="color: #777777;">[ 4.367160] TERM=linux</span>
<span style="color: #777777;">INIT: version 3.04 booting</span>
<span style="color: #777777;">Framebuffer /dev/fb0 not detected</span>
<span style="color: #777777;">Boot splashscreen disabled</span>
<span style="color: #777777;">Starting udev</span>
<span style="color: #777777;">[ 5.300386] udevd[137]: starting version 3.2.11</span>
<span style="color: #777777;">[ 5.380494] udevd[138]: starting eudev-3.2.11</span>
<span style="color: #777777;">[ 6.117599] mtdblock: MTD device 'boot0' is NAND, please consider using UBI block devices instead.</span>
<span style="color: #777777;">[ 6.173478] mtdblock: MTD device 'uboot' is NAND, please consider using UBI block devices instead.</span>
<span style="color: #777777;">[ 6.185120] mtdblock: MTD device 'secure_storage' is NAND, please consider using UBI block devices instead.</span>
<span style="color: #777777;">[ 6.279098] mtdblock: MTD device 'spi0.0' is NAND, please consider using UBI block devices instead.</span>
<span style="color: #777777;">[ 6.297818] mtdblock: MTD device 'sys' is NAND, please consider using UBI block devices instead.</span>
<span style="color: #777777;">[ 7.001016] EXT4-fs (mmcblk0p2): re-mounted. Quota mode: disabled.</span>
<span style="color: #777777;">hwclock: can't open '/dev/misc/rtc': No such file or directory</span>
<span style="color: #777777;">Fri Mar 9 12:34:56 UTC 2018</span>
<span style="color: #777777;">hwclock: can't open '/dev/misc/rtc': No such file or directory</span>
<span style="color: #777777;">INIT: Entering runlevel: 5</span>
<span style="color: #777777;">Configuring network interfaces... ifup: unknown address type "inet"</span>
<span style="color: #777777;">hwclock: can't open '/dev/misc/rtc': No such file or directory</span>
<span style="color: #777777;">Starting syslogd/klogd: done</span>
<span style="color: #777777;">OpenEmbedded nodistro.0 nezha-allwinner-d1 /dev/ttyS0</span>
<span style="color: #777777;">nezha-allwinner-d1 login:</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;"><b>NOTE</b>:<br />
</p><ul style="text-align: left;"><li>the build dates of U-Boot and the kernel are wrong because Yocto enables <a href="https://reproducible-builds.org/" target="_blank">reproducible builds</a> by default, so although it claims to have been build back in Nov 2022, this image was actually built late Jan 2023</li></ul><p></p>
<p style="text-align: left;">As this image boots, it runs U-Boot (starting at line 75 of the output above). The meta-riscv layer added a script to U-Boot (<span style="font-family: courier;">/boot.scr.uimg</span>) that it finds and runs as part of its boot process (line 105). The script looks like:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;"># This is the default TFTP and MMC u-boot boot script</span>
<span style="color: #777777; font-style: italic;"># The order is as follows:</span>
<span style="color: #777777; font-style: italic;"># 1. TFTP load a uEnv.txt</span>
<span style="color: #777777; font-style: italic;"># 2. TFTP boot a fitImage</span>
<span style="color: #777777; font-style: italic;"># 3. MMC load a uEnv.txt</span>
<span style="color: #777777; font-style: italic;"># 4. MMC load a fitImage</span>
<span style="color: #777777; font-style: italic;"># 5. TFTP load a uImage</span>
<span style="color: #777777; font-style: italic;"># 6. MMC load a fitImage</span>
<span style="color: #777777; font-style: italic;"># Setup the DHCP for a TFTP boot</span>
setenv serverip @SERVERIP@
dhcp
<span style="color: #777777; font-style: italic;"># See if we have a TFTP uEnv.txt file</span>
<span style="color: #6ab825; font-weight: bold;">if</span> tftpboot <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">scriptaddr</span><span style="color: #bf7f0f;">}</span> uEnv.txt; <span style="color: #6ab825; font-weight: bold;">then</span>
env import -t <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">scriptaddr</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">filesize</span><span style="color: #bf7f0f;">}</span>
run bootcmd
<span style="color: #6ab825; font-weight: bold;">fi</span>;
<span style="color: #777777; font-style: italic;"># Try to boot a fitImage from the TFTP server</span>
<span style="color: #6ab825; font-weight: bold;">if</span> tftpboot <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">ramdisk_addr_r</span><span style="color: #bf7f0f;">}</span> fitImage; <span style="color: #6ab825; font-weight: bold;">then</span>
bootm <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">ramdisk_addr_r</span><span style="color: #bf7f0f;">}</span>
<span style="color: #6ab825; font-weight: bold;">fi</span>;
<span style="color: #777777; font-style: italic;"># See if we have a MMC uEnv.txt file</span>
<span style="color: #6ab825; font-weight: bold;">if</span> fatload <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devtype</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devnum</span><span style="color: #bf7f0f;">}</span>:<span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">distro_bootpart</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">scriptaddr</span><span style="color: #bf7f0f;">}</span> /uEnv.txt; <span style="color: #6ab825; font-weight: bold;">then</span>
env import -t <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">scriptaddr</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">filesize</span><span style="color: #bf7f0f;">}</span>
run bootcmd
<span style="color: #6ab825; font-weight: bold;">fi</span>;
<span style="color: #777777; font-style: italic;"># Try to boot a fitImage from the MMC </span>
<span style="color: #6ab825; font-weight: bold;">if</span> load <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devtype</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devnum</span><span style="color: #bf7f0f;">}</span>:<span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">distro_bootpart</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">ramdisk_addr_r</span><span style="color: #bf7f0f;">}</span> fitImage; <span style="color: #6ab825; font-weight: bold;">then</span>
bootm <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">ramdisk_addr_r</span><span style="color: #bf7f0f;">}</span>
<span style="color: #6ab825; font-weight: bold;">fi</span>;
<span style="color: #777777; font-style: italic;"># Fallback to a TFTP uImage</span>
<span style="color: #6ab825; font-weight: bold;">if</span> tftpboot <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">kernel_addr_r</span><span style="color: #bf7f0f;">}</span> uImage; <span style="color: #6ab825; font-weight: bold;">then</span>
bootm <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">kernel_addr_r</span><span style="color: #bf7f0f;">}</span> - <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">fdt_addr_r</span><span style="color: #bf7f0f;">}</span>
<span style="color: #6ab825; font-weight: bold;">fi</span>;
<span style="color: #777777; font-style: italic;"># Finally fallback to a MMC uImage</span>
<span style="color: #6ab825; font-weight: bold;">if</span> load <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devtype</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devnum</span><span style="color: #bf7f0f;">}</span>:<span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">distro_bootpart</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">kernel_addr_r</span><span style="color: #bf7f0f;">}</span> uImage; <span style="color: #6ab825; font-weight: bold;">then</span>
bootm <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">kernel_addr_r</span><span style="color: #bf7f0f;">}</span> - <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">fdt_addr_r</span><span style="color: #bf7f0f;">}</span>
<span style="color: #6ab825; font-weight: bold;">fi</span>;
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">This script initializes networking and tries to download an environment and fitImage from a remote server. If those fail, then it tries to do the same from the SDcard. If you don't have a server and haven't provided its IP address to this script then these steps will fail. However, as U-Boot tries to download these items, those attempts have to timeout before it will mark those steps as having failed and proceed to the next steps. In the case where you don't have a server setup, these steps take quite a while to timeout. The boot log that I provided above shows the case where not only have I not setup a server but I also don't have an ethernet cable plugged into the Nezha board. If you do happen to have a cable plugged in (but still don't have a server setup), the boot looks a little different during the U-Boot phase, and takes even longer to timeout and move on to looking for the artifacts on the SDcard.</p><p style="text-align: left;">Here's what the U-Boot portion of the bootup looks like if you don't have a server setup, but you do have an ethernet cable plugged into the Nezha board, and you do have a DHCP server on this network:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">U-Boot 2022.10 (Nov 01 2022 - 04:27:57 +0000) Allwinner Technology</span>
<span style="color: #777777;">DRAM: 1 GiB </span>
<span style="color: #777777;">sunxi_set_gate: (CLK#24) unhandled</span>
<span style="color: #777777;">Core: 54 devices, 20 uclasses, devicetree: separate</span>
<span style="color: #777777;">WDT: Started watchdog@6011000 with servicing every 1000ms (16s timeout)</span>
<span style="color: #777777;">MMC: mmc@4020000: 0, mmc@4021000: 1</span>
<span style="color: #777777;">Loading Environment from FAT... PLL reg = 0xf8216300, freq = 1200000000</span>
<span style="color: #777777;">Unable to read "uboot.env" from mmc0:1... </span>
<span style="color: #777777;">In: serial@2500000</span>
<span style="color: #777777;">Out: serial@2500000</span>
<span style="color: #777777;">Err: serial@2500000</span>
<span style="color: #777777;">Net: </span>
<span style="color: #777777;">Warning: ethernet@4500000 (eth0) using random MAC address - 1e:06:7c:ef:f4:0c</span>
<span style="color: #777777;">eth0: ethernet@4500000</span>
<span style="color: #777777;">starting USB...</span>
<span style="color: #777777;">Bus usb@4101000: USB EHCI 1.00</span>
<span style="color: #777777;">Bus usb@4101400: USB OHCI 1.0 </span>
<span style="color: #777777;">Bus usb@4200000: USB EHCI 1.00</span>
<span style="color: #777777;">Bus usb@4200400: USB OHCI 1.0 </span>
<span style="color: #777777;">scanning bus usb@4101000 for devices... 1 USB Device(s) found</span>
<span style="color: #777777;">scanning bus usb@4101400 for devices... 1 USB Device(s) found</span>
<span style="color: #777777;">scanning bus usb@4200000 for devices... 1 USB Device(s) found</span>
<span style="color: #777777;">scanning bus usb@4200400 for devices... 1 USB Device(s) found</span>
<span style="color: #777777;"> scanning usb for storage devices... 0 Storage Device(s) found</span>
<span style="color: #777777;">Hit any key to stop autoboot: 2 ^H^H^H 1 ^H^H^H 0 </span>
<span style="color: #777777;">PLL reg = 0xf8216300, freq = 1200000000</span>
<span style="color: #777777;">switch to partitions #0, OK</span>
<span style="color: #777777;">mmc0 is current device</span>
<span style="color: #777777;">Scanning mmc 0:1...</span>
<span style="color: #777777;">Found U-Boot script /boot.scr.uimg</span>
<span style="color: #777777;">1249 bytes read in 1 ms (1.2 MiB/s)</span>
<span style="color: #777777;">## Executing script at 41900000</span>
<span style="color: #777777;">BOOTP broadcast 1</span>
<span style="color: #777777;">BOOTP broadcast 2</span>
<span style="color: #777777;">DHCP client bound to address 10.0.0.51 (987 ms) </span>
<span style="color: #777777;">*** Warning: no boot file name; using '0A000033.img'</span>
<span style="color: #777777;">Using ethernet@4500000 device</span>
<span style="color: #777777;">TFTP from server 127.0.0.1; our IP address is 10.0.0.51; sending through gateway 10.0.0.1</span>
<span style="color: #777777;">Filename '0A000033.img'.</span>
<span style="color: #777777;">Load address: 0x42000000</span>
<span style="color: #777777;">Loading: *^HT T T T T T T T T T </span>
<span style="color: #777777;">Retry count exceeded; starting again</span>
<span style="color: #777777;">Using ethernet@4500000 device</span>
<span style="color: #777777;">TFTP from server 127.0.0.1; our IP address is 10.0.0.51; sending through gateway 10.0.0.1</span>
<span style="color: #777777;">Filename 'uEnv.txt'.</span>
<span style="color: #777777;">Load address: 0x41900000</span>
<span style="color: #777777;">Loading: *^HT T T T T T T T T T </span>
<span style="color: #777777;">Retry count exceeded; starting again</span>
<span style="color: #777777;">Using ethernet@4500000 device</span>
<span style="color: #777777;">TFTP from server 127.0.0.1; our IP address is 10.0.0.51; sending through gateway 10.0.0.1</span>
<span style="color: #777777;">Filename 'fitImage'.</span>
<span style="color: #777777;">Load address: 0x41c00000</span>
<span style="color: #777777;">Loading: *^HT T T T T T T T T T </span>
<span style="color: #777777;">Retry count exceeded; starting again</span>
<span style="color: #777777;">322 bytes read in 1 ms (314.5 KiB/s)</span>
<span style="color: #777777;">5431248 bytes read in 898 ms (5.8 MiB/s)</span>
<span style="color: #777777;">## Loading kernel from FIT Image at 41c00000 ... </span>
<span style="color: #777777;"> Using 'conf-1' configuration</span>
<span style="color: #777777;"> Trying 'kernel-1' kernel subimage</span>
<span style="color: #777777;"> Description: Linux kernel</span>
<span style="color: #777777;"> Type: Kernel Image</span>
<span style="color: #777777;"> Compression: gzip compressed</span>
<span style="color: #777777;"> Data Start: 0x41c0010c</span>
<span style="color: #777777;"> Data Size: 5428090 Bytes = 5.2 MiB </span>
<span style="color: #777777;"> Architecture: RISC-V</span>
<span style="color: #777777;"> OS: Linux</span>
<span style="color: #777777;"> Load Address: 0x40200000</span>
<span style="color: #777777;"> Entry Point: 0x40200000</span>
<span style="color: #777777;"> Hash algo: sha256</span>
<span style="color: #777777;"> Hash value: c0897b7ecc8c79a67ffd0b71af8a90e3bdeb028c9953a13a8a4b2c0dab4e3797</span>
<span style="color: #777777;"> Verifying Hash Integrity ... sha256+ OK</span>
<span style="color: #777777;">## Flattened Device Tree blob at 7fd3e180</span>
<span style="color: #777777;"> Booting using the fdt blob at 0x7fd3e180</span>
<span style="color: #777777;">Working FDT set to 7fd3e180</span>
<span style="color: #777777;"> Uncompressing Kernel Image</span>
<span style="color: #777777;"> Loading Device Tree to 0000000042df2000, end 0000000042dffc27 ... OK</span>
<span style="color: #777777;">Working FDT set to 42df2000</span>
<span style="color: #777777;">Starting kernel ...</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">These timeouts take a very long time to expire (longer than the ones with the cable unplugged). While this is a way to do development, you might want to turn this off if you don't plan on using a server this way, or for production. One way to do this would be to create a <span style="font-family: courier;">bbappend</span> in one of your own layers:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span>└── recipes-bsp
└── u-boot
├── files
│ └── tftp-mmc-boot.txt
└── u-boot-nezha%.bbappend
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">set the <span style="font-family: courier;">bbappend</span> to contain:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span>FILESEXTRAPATHS:prepend := <span style="color: #bf7f0f;">"${</span><span style="color: #2db5b5;">THISDIR</span><span style="color: #bf7f0f;">}/files:"</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">and modify the script so that it only contains:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;"># This is the default TFTP and MMC u-boot boot script</span>
<span style="color: #777777; font-style: italic;"># The order is as follows:</span>
<span style="color: #777777; font-style: italic;"># 3. MMC load a uEnv.txt</span>
<span style="color: #777777; font-style: italic;"># 4. MMC load a fitImage</span>
<span style="color: #777777; font-style: italic;"># 6. MMC load a fitImage</span>
<span style="color: #777777; font-style: italic;"># See if we have a MMC uEnv.txt file</span>
<span style="color: #6ab825; font-weight: bold;">if</span> fatload <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devtype</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devnum</span><span style="color: #bf7f0f;">}</span>:<span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">distro_bootpart</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">scriptaddr</span><span style="color: #bf7f0f;">}</span> /uEnv.txt; <span style="color: #6ab825; font-weight: bold;">then</span>
env import -t <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">scriptaddr</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">filesize</span><span style="color: #bf7f0f;">}</span>
run bootcmd
<span style="color: #6ab825; font-weight: bold;">fi</span>;
<span style="color: #777777; font-style: italic;"># Try to boot a fitImage from the MMC</span>
<span style="color: #6ab825; font-weight: bold;">if</span> load <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devtype</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devnum</span><span style="color: #bf7f0f;">}</span>:<span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">distro_bootpart</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">ramdisk_addr_r</span><span style="color: #bf7f0f;">}</span> fitImage; <span style="color: #6ab825; font-weight: bold;">then</span>
bootm <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">ramdisk_addr_r</span><span style="color: #bf7f0f;">}</span>
<span style="color: #6ab825; font-weight: bold;">fi</span>;
<span style="color: #777777; font-style: italic;"># Finally fallback to a MMC uImage</span>
<span style="color: #6ab825; font-weight: bold;">if</span> load <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devtype</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">devnum</span><span style="color: #bf7f0f;">}</span>:<span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">distro_bootpart</span><span style="color: #bf7f0f;">}</span> <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">kernel_addr_r</span><span style="color: #bf7f0f;">}</span> uImage; <span style="color: #6ab825; font-weight: bold;">then</span>
bootm <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">kernel_addr_r</span><span style="color: #bf7f0f;">}</span> - <span style="color: #bf7f0f;">${</span><span style="color: #2db5b5;">fdt_addr_r</span><span style="color: #bf7f0f;">}</span>
<span style="color: #6ab825; font-weight: bold;">fi</span>;
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Build, flash, apply power. Now when the board boots, U-Boot won't try to get artifacts over the network and your boot will proceed much quicker.</p><h2 style="text-align: left;">GPIO</h2><p style="text-align: left;">The Nezha-D1 comes in a (roughly) Raspberry Pi form with a (roughly) Raspberry Pi 40-pin header. Using an SBC in a project often involves connecting devices to its header pins and then writing or adding software to manipulate the state of those pins. Learning how to "find" those pins programmatically is an important step towards working with any board. Before writing code to interact with the pins, we can experiment with them on the cmdline.</p><p style="text-align: left;">Starting with release 4.18, the Linux kernel revamped its GPIO subsystem. Therefore the interfaces and procedures to work with GPIOs changed. The current way (as of this writing) to interact with GPIOs from user-space involves working with <span style="font-family: courier;">libgpiod</span> and its tools. If you search for instructions to work with GPIOs on the internet, you might unknowingly come across old information. Under the new scheme individual GPIOs are called "<i>lines</i>". Each line is connected to and controlled by a "<i>gpio chip</i>".</p><p style="text-align: left;">To start with, we need to find a diagram or schematic describing each of the pins on the 40-pin header. Luckily the schematic for the Nezha board is available and can be found <a href="http://dl.linux-sunxi.org/D1/D1_Nezha_development_board_schematic_diagram_20210224.pdf" target="_blank">here</a>. Looking at the schematic, on page 7/9 we find the details of the 40-pin header (middle, lower, titled: IO EXPAND):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRPHx6DK2rSWAOZ3FcQCMIFFnpUcrqfGlCHgtFykjCzOxHK4sWFvn4zUPjgRViUQkFanZ31TQoOh39VO6r3nLoZNxWdbDy5cs2F9Gex16aMWEne00ytAj6TVI6s3ONQEiaBnb6bz2GMpHhxyFx_VojXzV_4ywavDzdRWP-0BHOtGbA3c0Gd3-xlivS/s669/nezha-schematic-gpio2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="546" data-original-width="669" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRPHx6DK2rSWAOZ3FcQCMIFFnpUcrqfGlCHgtFykjCzOxHK4sWFvn4zUPjgRViUQkFanZ31TQoOh39VO6r3nLoZNxWdbDy5cs2F9Gex16aMWEne00ytAj6TVI6s3ONQEiaBnb6bz2GMpHhxyFx_VojXzV_4ywavDzdRWP-0BHOtGbA3c0Gd3-xlivS/s16000/nezha-schematic-gpio2.png" /></a></div><p style="text-align: left;">This information pairs the pin number with the SoC's pin name. For example: pin 3, labeled "<i><span style="font-family: courier;">GPIO1/TWI2-SDA</span></i>", is connected to SoC pin <span style="font-family: courier;">PB1-S</span>. Looking at the SoC names we find: <span style="font-family: courier;">P<b>B</b><i>x</i>-S</span>, <span style="font-family: courier;">P<b>C</b><i>x</i>-S</span>, <span style="font-family: courier;">P<b>D</b><i>x</i>-S</span>, and <span style="font-family: courier;">P<b>P</b><i>x</i></span>. From experience, some SoCs do I/O via <i>ports</i> and have a couple ports to which I/O is connected. So I'm going to guess that <span style="font-family: courier;">PB</span>, for example, stands for "<i>Port B</i>" and that this board exposes portions of the SoC's ports labeled <b><span style="font-family: courier;">B</span></b> to <b><span style="font-family: courier;">D</span></b> ... and <b><span style="font-family: courier;">P</span></b>? At this point I'm fairly sure the P stands for "port", the next letter specifies which port (numbered alphabetically), and the next value is the specific pin of the given port. For example: <span style="font-family: courier;">PD15-S</span> is the 16th pin (counting from 0) of Port D.</p><p style="text-align: left;">I'm not sure what the "<span style="font-family: courier;">-S</span>" means. Looking back at the schematic:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipcZwjbKK_6I-jLWhbfDSGlYdBc5brIikJpVx2h5B_N4f3BnqtrRIOKUAeKEf9NBGtRMdE-IVkr9csiY_artl0ZZTeMYl4dP0gPxy72uPSC031JamxJEwn7gaOrMjSLgDVPn4fSG48Esj6JdimhPiuoL_9XiOUXBkO72ksPlTq_7mnW-W7-N4TJ5Xa/s651/nezha-schematic-gpio3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="651" data-original-width="445" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipcZwjbKK_6I-jLWhbfDSGlYdBc5brIikJpVx2h5B_N4f3BnqtrRIOKUAeKEf9NBGtRMdE-IVkr9csiY_artl0ZZTeMYl4dP0gPxy72uPSC031JamxJEwn7gaOrMjSLgDVPn4fSG48Esj6JdimhPiuoL_9XiOUXBkO72ksPlTq_7mnW-W7-N4TJ5Xa/s16000/nezha-schematic-gpio3.png" /></a></div><br /><p style="text-align: left;">it explains that the "<span style="font-family: courier;">-S</span>" values are simply the raw pins after passing through a resistor. So for the rest of this I'll just drop the "<span style="font-family: courier;">-S</span>" and treat the two synonymously.</p><p style="text-align: left;">On the 40-pin header we don't see any pins from port A, but we see:</p><div><ul style="text-align: left;"><li>ports B</li><ul><li>PB0 (pin 5)</li><li>PB1 (pin 3)</li><li>PB3 (pin 38)</li><li>PB4 (pin 40)</li><li>PB5 (pin 12)</li><li>PB6 (pin 35)</li><li>PB8 (pin 8)</li><li>PB9 (pin 10)</li><li>PB12 (pin 15)</li></ul><li>C</li><ul><li>PC1 (pin 31)</li></ul><li>D</li><ul><li>PD10 (pin 24)</li><li>PD11 (pin 23)</li><li>PD12 (pin 19)</li><li>PD13 (pin 21)</li><li>PD14 (pin 27)</li><li>PD15 (pin 29)</li><li>PD22 (pin 7)</li></ul><li>P</li><ul><li>PP0 (pin 13)</li><li>PP1 (pin 16)</li><li>PP2 (pin 18)</li><li>PP3 (pin 38)</li><li>PP4 (pin 40)</li><li>PP5 (pin 28)</li><li>PP6 (pin 37)</li><li>PP7 (pin 11)</li></ul><li>3V3</li><ul><li>pin 1</li><li>pin 17</li></ul><li>5V</li><ul><li>pin 2</li><li>pin 4</li></ul><li>GND</li><ul><li>pin 9</li><li>pin 25</li><li>pin 39</li><li>pin 6</li><li>pin 14</li><li>pin 20</li><li>pin 30</li><li>pin 34</li></ul></ul><p style="text-align: left;">Strangely, pins 32, 33, and 36 aren't connected to anything.</p><p style="text-align: left;">By this point I've already run some of the <span style="font-family: courier;">libgpiod</span> commands. Specifically I've run:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:~#</span> gpiodetect
<span style="color: #777777;">gpiochip0 [2000000.pinctrl] (224 lines)</span>
<span style="color: #777777;">gpiochip1 [pcf8574a] (8 lines)</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">This tells me that Linux is aware there are 2 gpio chips on this SoC. Digging a little deeper:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:~#</span> gpioinfo
<span style="color: #777777;">gpiochip0 - 224 lines:</span>
<span style="color: #777777;"> line 0: unnamed unused input active-high </span>
<span style="color: #777777;"> line 1: unnamed unused input active-high </span>
<span style="color: #777777;"> line 2: unnamed unused input active-high </span>
<span style="color: #777777;"> line 3: unnamed unused input active-high </span>
<span style="color: #777777;"> line 4: unnamed unused input active-high </span>
<span style="color: #777777;"> line 5: unnamed unused input active-high </span>
<span style="color: #777777;"> line 6: unnamed unused input active-high </span>
<span style="color: #777777;"> line 7: unnamed unused input active-high </span>
<span style="color: #777777;"> line 8: unnamed unused input active-high </span>
<span style="color: #777777;"> line 9: unnamed unused input active-high </span>
<span style="color: #777777;"> line 10: unnamed unused input active-high </span>
<span style="color: #777777;"> line 11: unnamed unused input active-high </span>
<span style="color: #777777;"> line 12: unnamed unused input active-high </span>
<span style="color: #777777;"> line 13: unnamed unused input active-high </span>
<span style="color: #777777;"> line 14: unnamed unused input active-high </span>
<span style="color: #777777;"> line 15: unnamed unused input active-high </span>
<span style="color: #777777;"> line 16: unnamed unused input active-high </span>
<span style="color: #777777;"> line 17: unnamed unused input active-high </span>
<span style="color: #777777;"> line 18: unnamed unused input active-high </span>
<span style="color: #777777;"> line 19: unnamed unused input active-high </span>
<span style="color: #777777;"> line 20: unnamed unused input active-high </span>
<span style="color: #777777;"> line 21: unnamed unused input active-high </span>
<span style="color: #777777;"> line 22: unnamed unused input active-high </span>
<span style="color: #777777;"> line 23: unnamed unused input active-high </span>
<span style="color: #777777;"> line 24: unnamed unused input active-high </span>
<span style="color: #777777;"> line 25: unnamed unused input active-high </span>
<span style="color: #777777;"> line 26: unnamed unused input active-high </span>
<span style="color: #777777;"> line 27: unnamed unused input active-high </span>
<span style="color: #777777;"> line 28: unnamed unused input active-high </span>
<span style="color: #777777;"> line 29: unnamed unused input active-high </span>
<span style="color: #777777;"> line 30: unnamed unused input active-high </span>
<span style="color: #777777;"> line 31: unnamed unused input active-high </span>
<span style="color: #777777;"> line 32: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 33: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 34: unnamed "interrupt" input active-high [used]</span>
<span style="color: #777777;"> line 35: unnamed unused input active-high </span>
<span style="color: #777777;"> line 36: unnamed unused input active-high </span>
<span style="color: #777777;"> line 37: unnamed unused input active-high </span>
<span style="color: #777777;"> line 38: unnamed unused input active-high </span>
<span style="color: #777777;"> line 39: unnamed unused input active-high </span>
<span style="color: #777777;"> line 40: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 41: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 42: unnamed unused input active-high </span>
<span style="color: #777777;"> line 43: unnamed unused input active-high </span>
<span style="color: #777777;"> line 44: unnamed unused input active-high </span>
<span style="color: #777777;"> line 45: unnamed unused input active-high </span>
<span style="color: #777777;"> line 46: unnamed unused input active-high </span>
<span style="color: #777777;"> line 47: unnamed unused input active-high </span>
<span style="color: #777777;"> line 48: unnamed unused input active-high </span>
<span style="color: #777777;"> line 49: unnamed unused input active-high </span>
<span style="color: #777777;"> line 50: unnamed unused input active-high </span>
<span style="color: #777777;"> line 51: unnamed unused input active-high </span>
<span style="color: #777777;"> line 52: unnamed unused input active-high </span>
<span style="color: #777777;"> line 53: unnamed unused input active-high </span>
<span style="color: #777777;"> line 54: unnamed unused input active-high </span>
<span style="color: #777777;"> line 55: unnamed unused input active-high </span>
<span style="color: #777777;"> line 56: unnamed unused input active-high </span>
<span style="color: #777777;"> line 57: unnamed unused input active-high </span>
<span style="color: #777777;"> line 58: unnamed unused input active-high </span>
<span style="color: #777777;"> line 59: unnamed unused input active-high </span>
<span style="color: #777777;"> line 60: unnamed unused input active-high </span>
<span style="color: #777777;"> line 61: unnamed unused input active-high </span>
<span style="color: #777777;"> line 62: unnamed unused input active-high </span>
<span style="color: #777777;"> line 63: unnamed unused input active-high </span>
<span style="color: #777777;"> line 64: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 65: unnamed unused input active-high </span>
<span style="color: #777777;"> line 66: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 67: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 68: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 69: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 70: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 71: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 72: unnamed unused input active-high</span>
<span style="color: #777777;"> line 73: unnamed unused input active-high</span>
<span style="color: #777777;"> line 74: unnamed unused input active-high</span>
<span style="color: #777777;"> line 75: unnamed unused input active-high</span>
<span style="color: #777777;"> line 76: unnamed unused input active-high</span>
<span style="color: #777777;"> line 77: unnamed unused input active-high</span>
<span style="color: #777777;"> line 78: unnamed unused input active-high</span>
<span style="color: #777777;"> line 79: unnamed unused input active-high</span>
<span style="color: #777777;"> line 80: unnamed unused input active-high</span>
<span style="color: #777777;"> line 81: unnamed unused input active-high</span>
<span style="color: #777777;"> line 82: unnamed unused input active-high</span>
<span style="color: #777777;"> line 83: unnamed unused input active-high</span>
<span style="color: #777777;"> line 84: unnamed unused input active-high</span>
<span style="color: #777777;"> line 85: unnamed unused input active-high</span>
<span style="color: #777777;"> line 86: unnamed unused input active-high</span>
<span style="color: #777777;"> line 87: unnamed unused input active-high</span>
<span style="color: #777777;"> line 88: unnamed unused input active-high</span>
<span style="color: #777777;"> line 89: unnamed unused input active-high</span>
<span style="color: #777777;"> line 90: unnamed unused input active-high</span>
<span style="color: #777777;"> line 91: unnamed unused input active-high</span>
<span style="color: #777777;"> line 92: unnamed unused input active-high</span>
<span style="color: #777777;"> line 93: unnamed unused input active-high</span>
<span style="color: #777777;"> line 94: unnamed unused input active-high</span>
<span style="color: #777777;"> line 95: unnamed unused input active-high</span>
<span style="color: #777777;"> line 96: unnamed unused input active-high</span>
<span style="color: #777777;"> line 97: unnamed unused input active-high</span>
<span style="color: #777777;"> line 98: unnamed unused input active-high</span>
<span style="color: #777777;"> line 99: unnamed unused input active-high</span>
<span style="color: #777777;"> line 100: unnamed unused input active-high</span>
<span style="color: #777777;"> line 101: unnamed unused input active-high</span>
<span style="color: #777777;"> line 102: unnamed unused input active-high</span>
<span style="color: #777777;"> line 103: unnamed unused input active-high</span>
<span style="color: #777777;"> line 104: unnamed unused input active-high</span>
<span style="color: #777777;"> line 105: unnamed unused input active-high</span>
<span style="color: #777777;"> line 106: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 107: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 108: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 109: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 110: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 111: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 112: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 113: unnamed unused input active-high</span>
<span style="color: #777777;"> line 114: unnamed unused input active-high</span>
<span style="color: #777777;"> line 115: unnamed "usbvbus" output active-high [used]</span>
<span style="color: #777777;"> line 116: unnamed "usb0_vbus_det" input active-high [used]</span>
<span style="color: #777777;"> line 117: unnamed "usb0_id_det" input active-high [used]</span>
<span style="color: #777777;"> line 118: unnamed unused input active-high</span>
<span style="color: #777777;"> line 119: unnamed unused input active-high</span>
<span style="color: #777777;"> line 120: unnamed unused input active-high</span>
<span style="color: #777777;"> line 121: unnamed unused input active-high</span>
<span style="color: #777777;"> line 122: unnamed unused input active-high</span>
<span style="color: #777777;"> line 123: unnamed unused input active-high</span>
<span style="color: #777777;"> line 124: unnamed unused input active-high</span>
<span style="color: #777777;"> line 125: unnamed unused input active-high</span>
<span style="color: #777777;"> line 126: unnamed unused input active-high</span>
<span style="color: #777777;"> line 127: unnamed unused input active-high</span>
<span style="color: #777777;"> line 128: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 129: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 130: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 131: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 132: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 133: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 134: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 135: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 136: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 137: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 138: unnamed unused input active-high</span>
<span style="color: #777777;"> line 139: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 140: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 141: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 142: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 143: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 144: unnamed unused input active-high</span>
<span style="color: #777777;"> line 145: unnamed unused input active-high</span>
<span style="color: #777777;"> line 146: unnamed unused input active-high</span>
<span style="color: #777777;"> line 147: unnamed unused input active-high</span>
<span style="color: #777777;"> line 148: unnamed unused input active-high</span>
<span style="color: #777777;"> line 149: unnamed unused input active-high</span>
<span style="color: #777777;"> line 150: unnamed unused input active-high</span>
<span style="color: #777777;"> line 151: unnamed unused input active-high</span>
<span style="color: #777777;"> line 152: unnamed unused input active-high</span>
<span style="color: #777777;"> line 153: unnamed unused input active-high</span>
<span style="color: #777777;"> line 154: unnamed unused input active-high</span>
<span style="color: #777777;"> line 155: unnamed unused input active-high</span>
<span style="color: #777777;"> line 156: unnamed unused input active-high</span>
<span style="color: #777777;"> line 157: unnamed unused input active-high</span>
<span style="color: #777777;"> line 158: unnamed unused input active-high</span>
<span style="color: #777777;"> line 159: unnamed unused input active-high</span>
<span style="color: #777777;"> line 160: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 161: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 162: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 163: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 164: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 165: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 166: unnamed "cd" input active-high [used]</span>
<span style="color: #777777;"> line 167: unnamed unused input active-high</span>
<span style="color: #777777;"> line 168: unnamed unused input active-high</span>
<span style="color: #777777;"> line 169: unnamed unused input active-high</span>
<span style="color: #777777;"> line 170: unnamed unused input active-high</span>
<span style="color: #777777;"> line 171: unnamed unused input active-high</span>
<span style="color: #777777;"> line 172: unnamed unused input active-high</span>
<span style="color: #777777;"> line 173: unnamed unused input active-high</span>
<span style="color: #777777;"> line 174: unnamed unused input active-high</span>
<span style="color: #777777;"> line 175: unnamed unused input active-high</span>
<span style="color: #777777;"> line 176: unnamed unused input active-high</span>
<span style="color: #777777;"> line 177: unnamed unused input active-high</span>
<span style="color: #777777;"> line 178: unnamed unused input active-high</span>
<span style="color: #777777;"> line 179: unnamed unused input active-high</span>
<span style="color: #777777;"> line 180: unnamed unused input active-high</span>
<span style="color: #777777;"> line 181: unnamed unused input active-high</span>
<span style="color: #777777;"> line 182: unnamed unused input active-high</span>
<span style="color: #777777;"> line 183: unnamed unused input active-high</span>
<span style="color: #777777;"> line 184: unnamed unused input active-high</span>
<span style="color: #777777;"> line 185: unnamed unused input active-high</span>
<span style="color: #777777;"> line 186: unnamed unused input active-high</span>
<span style="color: #777777;"> line 187: unnamed unused input active-high</span>
<span style="color: #777777;"> line 188: unnamed unused input active-high</span>
<span style="color: #777777;"> line 189: unnamed unused input active-high</span>
<span style="color: #777777;"> line 190: unnamed unused input active-high</span>
<span style="color: #777777;"> line 191: unnamed unused input active-high</span>
<span style="color: #777777;"> line 192: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 193: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 194: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 195: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 196: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 197: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 198: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 199: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 200: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 201: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 202: unnamed unused input active-high</span>
<span style="color: #777777;"> line 203: unnamed unused input active-high</span>
<span style="color: #777777;"> line 204: unnamed "reset" output active-low [used]</span>
<span style="color: #777777;"> line 205: unnamed unused input active-high</span>
<span style="color: #777777;"> line 206: unnamed unused input active-high</span>
<span style="color: #777777;"> line 207: unnamed unused input active-high</span>
<span style="color: #777777;"> line 208: unnamed unused input active-high</span>
<span style="color: #777777;"> line 209: unnamed unused input active-high</span>
<span style="color: #777777;"> line 210: unnamed unused input active-high</span>
<span style="color: #777777;"> line 211: unnamed unused input active-high</span>
<span style="color: #777777;"> line 212: unnamed unused input active-high</span>
<span style="color: #777777;"> line 213: unnamed unused input active-high</span>
<span style="color: #777777;"> line 214: unnamed unused input active-high</span>
<span style="color: #777777;"> line 215: unnamed unused input active-high</span>
<span style="color: #777777;"> line 216: unnamed unused input active-high</span>
<span style="color: #777777;"> line 217: unnamed unused input active-high</span>
<span style="color: #777777;"> line 218: unnamed unused input active-high</span>
<span style="color: #777777;"> line 219: unnamed unused input active-high</span>
<span style="color: #777777;"> line 220: unnamed unused input active-high</span>
<span style="color: #777777;"> line 221: unnamed unused input active-high</span>
<span style="color: #777777;"> line 222: unnamed unused input active-high</span>
<span style="color: #777777;"> line 223: unnamed unused input active-high</span>
<span style="color: #777777;">gpiochip1 - 8 lines:</span>
<span style="color: #777777;"> line 0: unnamed unused input active-high</span>
<span style="color: #777777;"> line 1: unnamed unused input active-high</span>
<span style="color: #777777;"> line 2: unnamed unused input active-high</span>
<span style="color: #777777;"> line 3: unnamed unused input active-high</span>
<span style="color: #777777;"> line 4: unnamed unused input active-high</span>
<span style="color: #777777;"> line 5: unnamed unused input active-high</span>
<span style="color: #777777;"> line 6: unnamed unused input active-high</span>
<span style="color: #777777;"> line 7: unnamed unused input active-high</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">This doesn't help us too much, at least not immediately. Sometimes, if we're lucky, these lines will have more meaningful names (which are specified in the board's device-tree) but that's not the case here. We have to dig a little deeper to figure out how these lines relate to the <i>port</i> names we identified in the schematic.</p><p style="text-align: left;">Looking through the source for the kernel that we're using, we come across: <a href="https://github.com/smaeul/linux/blob/d1/all/drivers/pinctrl/sunxi/pinctrl-sunxi.h#L19">https://github.com/smaeul/linux/blob/d1/all/drivers/pinctrl/sunxi/pinctrl-sunxi.h#L19</a></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_FqMxKEOElE37hU58wiuWh3kJfDO3pymNUoVk8fxaemQ3yHSA7TjdHkmDDyULC75thjh4nGdA8B0HnuKybFprTlhydXX2w4rXlG4xVMoBOB_betwZNOZxRkknD6r7fNjXHjfnRZ969tp9KzjLvwy2Sduju7EmkJt6KlzSeFJCuRv2-zv9-BGe453-/s242/nezha-port-defines.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="242" data-original-width="195" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_FqMxKEOElE37hU58wiuWh3kJfDO3pymNUoVk8fxaemQ3yHSA7TjdHkmDDyULC75thjh4nGdA8B0HnuKybFprTlhydXX2w4rXlG4xVMoBOB_betwZNOZxRkknD6r7fNjXHjfnRZ969tp9KzjLvwy2Sduju7EmkJt6KlzSeFJCuRv2-zv9-BGe453-/s1600/nezha-port-defines.png" width="195" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p style="text-align: left;">This looks interesting. Previously <span style="font-family: courier;">gpioinfo</span> told us that <span style="font-family: courier;">gpiochip0</span> has 224 lines (0 to 223). Looking at this header file (<span style="font-family: courier;">drivers/pinctrl/sunxi/pinctrl-sunxi.h</span>) it looks like, on sunxi SoCs, each port has 32 pins. 224 is evenly divisible by 32, which implies this SoC has 7 ports: PortA through PortG. At this point I'll take a guess that we can now find all the <span style="font-family: courier;">PB<i>x</i></span> to <span style="font-family: courier;">PD<i>x</i></span> pins that are described in the schematic. For example, if we want to work with pin 40 on the header, aka <span style="font-family: courier;">GPIO25-I2S2-DOUT</span>, aka <span style="font-family: courier;">PB4</span>, I'm betting we'll find it on <span style="font-family: courier;">gpiochip0</span> line 36 since PortB starts at offset 32, and 32 + 4 = 36. <span style="font-family: courier;">PC1</span>, on the oher hand, would be on <span style="font-family: courier;">gpiochip0</span> line 65 since PortC starts at offset 64.</p><p style="text-align: left;">We can wire up a simple circuit to test this theory:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5kL9vaxUwZBWH7goXh6eGJuALwElyTjHS-s6qWMeo46c-hRZkgTPV1tzUf1PRaAhk818O7HoBmjrrhUUevcUNQRtRkWrICDzuIe5Cj8wD_YMTNXj-MtdA5p_iOOcmQA3Ul1mSV3JlIZmhsaLBNyxMAxk9YGI3BKoI_CLJ3GCh97EmTUbrFl7bFd16/s1755/nezha-led_bb.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1518" data-original-width="1755" height="554" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5kL9vaxUwZBWH7goXh6eGJuALwElyTjHS-s6qWMeo46c-hRZkgTPV1tzUf1PRaAhk818O7HoBmjrrhUUevcUNQRtRkWrICDzuIe5Cj8wD_YMTNXj-MtdA5p_iOOcmQA3Ul1mSV3JlIZmhsaLBNyxMAxk9YGI3BKoI_CLJ3GCh97EmTUbrFl7bFd16/w640-h554/nezha-led_bb.png" width="640" /></a></div><b>NOTE:</b></div><div><ul style="text-align: left;"><li>I have a bunch of LEDs that have the resistor build-in, hence the lack of resistor</li></ul><p style="text-align: left;">Then we can test with:</p><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 16.25px; margin: 5px;">1</pre></td><td><pre style="color: #4a364d; line-height: 16.25px; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:~#</span> gpioset gpiochip0 <span style="color: #2db5b5;">36</span>=<span style="color: #3677a9;">1</span></pre></td></tr></tbody></table></div><p style="text-align: left;">and we get:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPPePv_5sn4dTinbm5M4DNkLQ640NW8t5jJDPRz50mzBcgaJjNBqeAS7gb8CULInjLsmSPFwxcrTSSmCDD5MxRksNFoQSShff2uVg0H8kG_SwtVkg---cJHJOnd7NXPKo02BBzBrmWzSA37kK9Pv-WqGczKdzsGhb88K3YqQq4_FAQHQ0XoGBqNdaT/s512/nezha-gpio.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPPePv_5sn4dTinbm5M4DNkLQ640NW8t5jJDPRz50mzBcgaJjNBqeAS7gb8CULInjLsmSPFwxcrTSSmCDD5MxRksNFoQSShff2uVg0H8kG_SwtVkg---cJHJOnd7NXPKo02BBzBrmWzSA37kK9Pv-WqGczKdzsGhb88K3YqQq4_FAQHQ0XoGBqNdaT/s16000/nezha-gpio.png" /></a></div><br />We can move the wire from pin 40 to other pins and test our calculations.<p style="text-align: left;">But what about those "Port P" pins? In the schematic we found some pins labeled <span style="font-family: courier;">PP[0-7].</span><span style="font-family: inherit;"> </span>The kernel only has support for I/O up to Port N (in theory), and this specific SoC only appears to have I/O up to Port G (inclusive, according to <span style="font-family: courier;">gpioinfo</span>). Looking again at the schematic (page 7/9, bottom left):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUpwkE4gEZJPnqcGCjV83yP2aV97o8KXsAZxlkrP8gQkNRfCIVmnzSP1pdaXY7odtgZL8aFruOQ5BGdo1BhTW0J9ClVYM2c9fZSM74USg2yxAVE9-61Iyyaj4vpq0oUNol9zjcKjHa3OaEBkhN9LfKiXgpxQfMe3NsLnHWNp9qIH65bVlFpRfiIoId/s642/nezha-schematic-expander.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="287" data-original-width="642" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUpwkE4gEZJPnqcGCjV83yP2aV97o8KXsAZxlkrP8gQkNRfCIVmnzSP1pdaXY7odtgZL8aFruOQ5BGdo1BhTW0J9ClVYM2c9fZSM74USg2yxAVE9-61Iyyaj4vpq0oUNol9zjcKjHa3OaEBkhN9LfKiXgpxQfMe3NsLnHWNp9qIH65bVlFpRfiIoId/s16000/nezha-schematic-expander.png" /></a></div><br /><p style="text-align: left;">The designers of this board have decided to use a port expander for 8 of the pins in the 40-pin header. A port expander is a chip that allows you access to a larger number of IOs using a smaller number of SoC IOs. This IO expander, the PCF857x, is an I2C device. If you look carefully at this diagram and the schematic diagram of the 40-pin header, you'll notice that 2 pins from the 40-pin header (<span style="font-family: courier;">PB0</span> and <span style="font-family: courier;">PB1</span>) are used to control this PCF857x and these 2 pins can be used to control the 8 <span style="font-family: courier;">PP<i>x</i></span> pins!</p><p style="text-align: left;">Now that we understand how these <span style="font-family: courier;">PP<i>x</i></span> pins are accessed, how do we go about accessing them? The good news is that <i>we</i> don't have to figure out how to access them since <i>Linux</i> already takes care of this for us. The Linux kernel already has a driver for the PCF857x (<span style="font-family: courier;">drivers/gpio/gpio-pcf857x.c</span>) so all that's needed to get this to work is some glue logic in the device tree to associate <span style="font-family: courier;">PB0</span> to the PCF857x's <span style="font-family: courier;">SCK</span> signal and <span style="font-family: courier;">PB1</span> with <span style="font-family: courier;">SDA</span>. Thankfully this is already done for us in the Nezha's device tree (<a href="https://github.com/smaeul/linux/blob/d1/all/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts#L116">https://github.com/smaeul/linux/blob/d1/all/arch/riscv/boot/dts/allwinner/sun20i-d1-nezha.dts#L116</a>):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI0kWMsmesE1behQdMS5vkVvyZLN1wxKMes-EcluGg9QkkmtXcaKOcB61rhB1aq7E2BbuG-J8yMdhfQ97Qfcr9GRmE-H1ER3bNrE0636tW8e2fcLPNdWDZOPlaLdmTO3fEN96mgikWFp52ODGfs4iW_smWXINgmfosD2sXy6vVOkxXAsikWUSsygBh/s524/nezha-dt-pcf857x.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="322" data-original-width="524" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI0kWMsmesE1behQdMS5vkVvyZLN1wxKMes-EcluGg9QkkmtXcaKOcB61rhB1aq7E2BbuG-J8yMdhfQ97Qfcr9GRmE-H1ER3bNrE0636tW8e2fcLPNdWDZOPlaLdmTO3fEN96mgikWFp52ODGfs4iW_smWXINgmfosD2sXy6vVOkxXAsikWUSsygBh/s16000/nezha-dt-pcf857x.png" /></a></div><div><br /></div>If we look at the schematic for the PCF857x that is used on the Nezha, we see that it has an interrupt line that is connected to <span style="font-family: courier;">PB2</span> (which is confirmed in the comments in the device-tree above). Comparing "<span style="font-family: courier;">PB2</span>" with how the interrupt is specified "<span style="font-family: courier;">1 2 IRQ_TYPE_LEVEL_LOW</span>" it's a good bet that, for this SoC, interrupts are specified as: first number = port, second number = line. Using zero-based counting Port B = 1, and offset 2 = 2.<br /><p style="text-align: left;">If we look back at what the kernel told us about its GPIO setup we see:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5
6
7</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:~#</span> gpioinfo
<span style="color: #777777;">gpiochip0 - 224 lines:</span>
<span style="color: #777777;">…</span>
<span style="color: #777777;"> line 32: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 33: unnamed kernel input active-high [used]</span>
<span style="color: #777777;"> line 34: unnamed "interrupt" input active-high [used]</span>
<span style="color: #777777;">…</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">This meshes exactly with what we've just discovered: <span style="font-family: courier;">gpiochip0</span> lines <span style="font-family: courier;">32</span> and <span style="font-family: courier;">33</span> are <span style="font-family: courier;">PB0</span> and <span style="font-family: courier;">PB1</span> (since the offset for Port B is 32 on this device). We also see that line <span style="font-family: courier;">34</span>, <span style="font-family: courier;">PB2</span>, is marked as an interrupt. <span style="font-family: courier;">gpioinfo</span> marks all 3 lines as being in-use (and therefore not available for us to poke and peek).</p><p style="text-align: left;">Now that we've got all of that figured out, how do we access the PP<i>x</i> pins that come off the GPIO expander? It's probably not a coincidence that gpioinfo told us that there are 8 lines on gpiochip1 and that the PCF857x GPIO expander has 8 pins:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:~#</span> gpioinfo gpiochip1
<span style="color: #777777;">gpiochip1 - 8 lines:</span>
<span style="color: #777777;"> line 0: unnamed unused input active-high </span>
<span style="color: #777777;"> line 1: unnamed unused input active-high </span>
<span style="color: #777777;"> line 2: unnamed unused input active-high </span>
<span style="color: #777777;"> line 3: unnamed unused input active-high </span>
<span style="color: #777777;"> line 4: unnamed unused input active-high </span>
<span style="color: #777777;"> line 5: unnamed unused input active-high </span>
<span style="color: #777777;"> line 6: unnamed unused input active-high </span>
<span style="color: #777777;"> line 7: unnamed unused input active-high</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">If we look at the Linux kernel's driver for the PCF857x (<span style="font-family: courier;">drivers/gpio/gpio-pcf857x.c</span>) we find (<a href="https://github.com/smaeul/linux/blob/d1/all/drivers/gpio/gpio-pcf857x.c#L376">https://github.com/smaeul/linux/blob/d1/all/drivers/gpio/gpio-pcf857x.c#L376</a>):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQ1JU8SDoIzo2KM6G3YGpDwpUIlutQHG20ceNciF0NqjgC-YHe3LNqkpcEJPC9xqqTP737bqHkcwV5SNUsLwK_mF_QWpw4vyIPpyuGX7NPkspWGgJW4NAzplwRQu3DsStrtHX0ClQSQxUIOCL9ssTRR7Xf2Qeinpv6prGzFxlv3t58iR1LNrU3NkgG/s584/nezha-pcf857x.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="22" data-original-width="584" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQ1JU8SDoIzo2KM6G3YGpDwpUIlutQHG20ceNciF0NqjgC-YHe3LNqkpcEJPC9xqqTP737bqHkcwV5SNUsLwK_mF_QWpw4vyIPpyuGX7NPkspWGgJW4NAzplwRQu3DsStrtHX0ClQSQxUIOCL9ssTRR7Xf2Qeinpv6prGzFxlv3t58iR1LNrU3NkgG/s16000/nezha-pcf857x.png" /></a></div><p style="text-align: left;">This proves the connection between GPIO expanders and gpiochips. In the Linux kernel, GPIO expanders are exposed as gpiochips. In fact, if we looked carefully at the output of <span style="font-family: courier;">gpiodetect</span> we would have noticed that the kernel was already telling us that <span style="font-family: courier;">gpiochip1</span> is connected to the PCF857x:</p><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 16.25px; margin: 5px;">1
2
3</pre></td><td><pre style="color: #4a364d; line-height: 16.25px; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:~#</span> gpiodetect
<span style="color: #777777;">gpiochip0 [2000000.pinctrl] (224 lines)</span>
<span style="color: #777777;"><b><i>gpiochip1 [pcf8574a] (8 lines)</i></b></span></pre></td></tr></tbody></table></div><p style="text-align: left;">Let's test this. I'm going to arbitrarily pick <span style="font-family: courier;">PP6</span>, pin 37, and wire up the following test:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhoxEnnu1Mky8yhL6_0lSKaxNxGEGZm-1HO_Akj8vkA1WCBEv-dy_SoWAiFrxEv6suktq9ZUqmzfe5PVV0vYcvkHLywRYgtdg34DLq20jtFkkLeLWn9i9mdNum-D0rtGIRrotPlUjoTSP1NWRgVoMPobSRPGfPC3e4sNIq8BYqfjh1u0Hl2E0tomH1/s1755/nezha-led-gpioX_bb.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1518" data-original-width="1755" height="554" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhoxEnnu1Mky8yhL6_0lSKaxNxGEGZm-1HO_Akj8vkA1WCBEv-dy_SoWAiFrxEv6suktq9ZUqmzfe5PVV0vYcvkHLywRYgtdg34DLq20jtFkkLeLWn9i9mdNum-D0rtGIRrotPlUjoTSP1NWRgVoMPobSRPGfPC3e4sNIq8BYqfjh1u0Hl2E0tomH1/w640-h554/nezha-led-gpioX_bb.png" width="640" /></a></div></div><div><p style="text-align: left;">run:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:~#</span> gpioset gpiochip1 <span style="color: #2db5b5;">6</span>=<span style="color: #3677a9;">1</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">and:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYY5wQbuVMPTSgVqFcuc4s_YWBR5wQBsHIu-5PYqhQ8Rcu58B-Hwsc-faVJgCok0KQ-LybAqDYBrgbGqsiVYjRHxak8U9jFt9SYKV_vPJzBPGayZb8PBPf-cQVW_-geiOI2Es6rYAXRnaQyo6VywABBULd4yB2wkhubhs6_xcWck9LBw-Ul6E0dmCw/s512/nezha-gpioX-1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYY5wQbuVMPTSgVqFcuc4s_YWBR5wQBsHIu-5PYqhQ8Rcu58B-Hwsc-faVJgCok0KQ-LybAqDYBrgbGqsiVYjRHxak8U9jFt9SYKV_vPJzBPGayZb8PBPf-cQVW_-geiOI2Es6rYAXRnaQyo6VywABBULd4yB2wkhubhs6_xcWck9LBw-Ul6E0dmCw/s16000/nezha-gpioX-1.png" /></a></div><br /><p style="text-align: left;">nothing happens? It looks like the LED didn't come on. If you look closely, and possibly also dim the room lights, you'll see that the LED did, in fact, come on, though very dimly. At first this seems strange since the schematic shows the PCF857x as being connected to 3V3, so its output should be 3V3, and that should be enough to light the LED more visibly.</p><p style="text-align: left;">I'm not an electrical engineer so I don't know all the details of "why", but the short version is: the PCF857x is better at making zeros than it is at making ones. Trying to drive the LED by connecting the cathode (aka negative/short) of the LED to ground and the anode (aka positive/long pin) to the GPIO isn't going to work as well as we would expect. Instead, when working with the PCF957x, connect the cathode (aka negative/short pin) to the GPIO and the anode (positive/long pin) to 3V3 (we connect to 3V3 and not 5V since the PCF847x is using 3V3 for VDD, see the schematic for the Nezha board):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdmQ2Omku_PWf-BL4TH3GO-dl3TDVnZ4KD37n5fGPvCGyO_WpyynaksL7BYbw64Dh4ExAEirewALlMIYCUc2fMxGpMZ34LXXB_49VhvW4s6ylB4bpJNbtCYSRc9l9ADy-KuRGYMofqZQVo_9mAOm-xtU9cyzTAg8AkTxC9SVGCb-lejTxxl4u3evTO/s1755/nezha-gpioX-2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1518" data-original-width="1755" height="554" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdmQ2Omku_PWf-BL4TH3GO-dl3TDVnZ4KD37n5fGPvCGyO_WpyynaksL7BYbw64Dh4ExAEirewALlMIYCUc2fMxGpMZ34LXXB_49VhvW4s6ylB4bpJNbtCYSRc9l9ADy-KuRGYMofqZQVo_9mAOm-xtU9cyzTAg8AkTxC9SVGCb-lejTxxl4u3evTO/w640-h554/nezha-gpioX-2.png" width="640" /></a></div><p style="text-align: left;">This time we perform:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:~#</span> gpioset gpiochip1 <span style="color: #2db5b5;">6</span>=<span style="color: #3677a9;">0</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">and get what we're expecting (a brightly lit led):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNd2YWKUy27W4VW0uG760SOn9mSeajuUk-0axLlWhwV9qTo8SNg3ZIUImN_rS1B-F9M-muJWJA6EfGRGg-WtqjwKeK91VxKa8nL_PSjSCCPuzf7U9zaLyJTZYkfJxYMD5pa-MLE63uVb79HuJ_kbY4fEM5V-qGn-ieSM30yAsuUFvGE44ExnOfI6jx/s512/nezha-gpioX-2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNd2YWKUy27W4VW0uG760SOn9mSeajuUk-0axLlWhwV9qTo8SNg3ZIUImN_rS1B-F9M-muJWJA6EfGRGg-WtqjwKeK91VxKa8nL_PSjSCCPuzf7U9zaLyJTZYkfJxYMD5pa-MLE63uVb79HuJ_kbY4fEM5V-qGn-ieSM30yAsuUFvGE44ExnOfI6jx/s16000/nezha-gpioX-2.png" /></a></div><br /><p style="text-align: left;">As you've probably noticed, the logic with this wiring is backwards. If <span style="font-family: courier;">PP6</span> is set to 1 then both wires feeding the LED will be giving it 3V3, turning it off. But if you set <span style="font-family: courier;">PP6</span> to 0 then there will be a potential across the LED and it will turn on. Using the GPIO for the zero, and holding the other side of the LED at 3V3 is why we had to turn the LED around and connect the GPIO to the anode.</p><h2 style="text-align: left;">RGB LED</h2><p style="text-align: left;">Another neat thing about the Nezha board is that it has a user-controlled <i>RGB</i> LED (instead of just a regular single-colour LED). Interestingly enough, the AllWinner SoC has an RGB LED controller (called <span style="font-family: courier;">ledc</span>), and the Linux kernel has a driver for it: <span style="font-family: courier;">CONFIG_LEDS_SUN50I_A100</span>.</p><p style="text-align: left;">If you used the exact SHA1 checkout for your build as I used above, then you'll find a small issue with the meta-riscv layer in that it is using an older name for the driver in its <span style="font-family: courier;">defconfig</span>. As a result, support for the RGB LED is not enabled correctly. That's been fixed, so upgrading to a more recent commit should work better.</p><p style="text-align: left;">With a correctly-working kernel, in user-space you can navigate (on the Nezha board) to <span style="font-family: courier;">/sys/class/leds/rgb:status</span> and play with the RGB LED.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:/sys/class/leds/rgb:status#</span> ls -l
<span style="color: #777777;">total 0</span>
<span style="color: #777777;">-rw-r--r-- 1 root root 4096 Jan 30 19:22 brightness</span>
<span style="color: #777777;">lrwxrwxrwx 1 root root 0 Jan 30 20:34 device -> ../../../2008000.led-controller</span>
<span style="color: #777777;">-r--r--r-- 1 root root 4096 Jan 30 20:34 max_brightness</span>
<span style="color: #777777;">-r--r--r-- 1 root root 4096 Jan 30 20:34 multi_index</span>
<span style="color: #777777;">-rw-r--r-- 1 root root 4096 Jan 30 19:50 multi_intensity</span>
<span style="color: #777777;">drwxr-xr-x 2 root root 0 Jan 30 20:34 power</span>
<span style="color: #777777;">lrwxrwxrwx 1 root root 0 Dec 20 13:15 subsystem -> ../../../../../../class/leds</span>
<span style="color: #777777;">-rw-r--r-- 1 root root 0 Jan 30 19:18 trigger</span>
<span style="color: #777777;">-rw-r--r-- 1 root root 4096 Dec 20 13:15 uevent</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">First, take a look at the output from <span style="font-family: courier;">multi_index</span>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:/sys/class/leds/rgb:status#</span> cat multi_index
<span style="color: #777777;">red green blue</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">This tells you the expected order of LED values. Check the <span style="font-family: courier;">max_brightness</span>, set the <span style="font-family: courier;">brightness</span> to something small (no need to burn your retinas), and specify your red, green, and blue values:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:/sys/class/leds/rgb:status#</span> cat max_brightness
<span style="color: #777777;">255</span>
<span style="color: #348c00;">root@nezha-allwinner-d1:/sys/class/leds/rgb:status#</span> echo <span style="color: #3677a9;">15</span> > brightness
<span style="color: #348c00;">root@nezha-allwinner-d1:/sys/class/leds/rgb:status#</span> echo <span style="color: #bf7f0f;">"0 0 255"</span> > multi_intensity
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Your RGB LED will now be blue:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6b6TqUEkOtJziUAZPTY_w2vO8E32itM_fFfxnrKHFpjALRbOYCfcrkqS22Ve6Z6QQx4DZMPfOCez_iEFDW2Mblax2ZoVQBFuR-FHa2IoB0ZsZUGgKi5jHrbGYFs-R5REIXcXHcpo7zI3y_KgvW5dJ0BNxdwhAiUZCs4kHjlXyxLolV9_zgF9vvE87/s512/nezha-blue.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6b6TqUEkOtJziUAZPTY_w2vO8E32itM_fFfxnrKHFpjALRbOYCfcrkqS22Ve6Z6QQx4DZMPfOCez_iEFDW2Mblax2ZoVQBFuR-FHa2IoB0ZsZUGgKi5jHrbGYFs-R5REIXcXHcpo7zI3y_KgvW5dJ0BNxdwhAiUZCs4kHjlXyxLolV9_zgF9vvE87/s16000/nezha-blue.png" /></a></div><br /><p style="text-align: left;">You can play with other combinations to your heart's content, or you could download and run <a href="https://github.com/twoerner/rgb-led-test" target="_blank">this little script</a> I wrote to randomly set the values for you continuously (run it in the background).</p><p style="text-align: left;">Another neat thing to do with a user-led is to ask the kernel to control it to provide various types of feedback. For example, you can set the LED to provide a "heartbeat" to prove your board is alive:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@nezha-allwinner-d1:/sys/class/leds/rgb:status#</span> cat trigger
<span style="color: #777777;">[none] kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock timer oneshot mtd nand-disk heartbeat cpu cpu0 activity panic netdev mmc0 mmc1</span>
<span style="color: #348c00;">root@nezha-allwinner-d1:/sys/class/leds/rgb:status#</span> echo <span style="color: #bf7f0f;">"20 0 20"</span> > multi_intensity
<span style="color: #348c00;">root@nezha-allwinner-d1:/sys/class/leds/rgb:status#</span> echo heartbeat > trigger
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Interestingly, in trigger mode the global <span style="font-family: courier;">brightness</span> doesn't seem to have any effect. Brightness is set by the individual values of <span style="font-family: courier;">multi_intensity</span>. Not sure if that's a bug or a feature.</p><p></p><p></p></div>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-71645146061012368252023-01-27T23:37:00.000-05:002023-01-27T23:37:18.768-05:00Coordinated Holiday Lights - base software<p>My goal is to put together a set of devices that will allow me to coordinate the turning on and turning off of various holiday lights around a large property. These devices are plugged into mains power and provide an outlet (to which the load is connected) whose state is controlled by the electronics inside the box. By this time I've built four such boxes and it is time to start thinking about software. I'm using Linux-capable single board computers (SBCs) in each box. As an added twist I've decided to use a different SBC in each box. So far I've used:</p><p></p><ul style="text-align: left;"><li>raspberry pi 3</li><li>olimex imx233-olinuxino-maxi</li><li>rock pi e</li><li>beagleboard black</li></ul><p style="text-align: left;">When a manufacturer puts out an SBC, they always provide some sort of software to show off the device. If they're going to claim their new SBC has certain capabilities, then they need to provide some software in order to benchmark their claims. This software is more often than not provided as a monolithic binary image: "download this file, flash it to an SDcard, insert the SDcard into the SBC, and apply power".</p><p style="text-align: left;">Since there is no single, universally accepted, correct, Linux image/system to use, vendors are free to put together their images however they wish (or however then can). Some are deb-based, others use rpm; some don't even have a package manager. Some use sysvinit, others systemd. Some use X, others will use Wayland. Some will use busybox components, others will use the full utilities (coreutils). Some are based on recent versions of software, others are based on software that is quite old the day the SBC is released. All of these choices affect the user experience. How do you start a daemon? How do you configure networking? How do you set the state of a GPIO pin? These procedures are all different depending on which choices were made earlier. For example: the seemingly simple task of setting a GPIO will be frustrating for the user if the SBC has an old kernel and the user's search finds them instructions for a recent kernel, or instructions that use a tool that isn't available in the manufacturer's image, or instructions that use an option for a tool that wasn't enabled in the tool that is in the manufacturer's image.</p><p style="text-align: left;">Putting together an image is not a trivial activity. Maintaining an image and keeping it up-to-date throughout the lifecycle of a product (which includes development!) is even more work. As it turns out, there are tools that can be used to create an image. Some image-creation tools can even help with the on-going maintenance of an image over its lifetime. But is the manufacturer aware of these tools when they put together their image? Did they use these tools, or slap something together in-house? Is the image they create using common idioms and conventions, or is it an anomaly with quirks unlike anything else you'll find anywhere else in the Linux world? There is a cost that goes along with learning how to use a tool (and learning how to use it well), slapping something together haphazardly often feels faster and easier (especially in the short term).</p><p style="text-align: left;">If a user buys an SBC because they want to use it for a specific project they have in mind, they usually don't want to spend any time putting together their own images; they want to get going on their project, and rarely is their project "to put together an image for this SBC". Therefore the easiest way to get started is to use the manufacturer-provided image. However, the software the manufacturer provides will only include whatever the manufacturer thought was important in order to quantify whatever it is they wish to benchmark. <b><i>These manufacturer-provided images are "show-off" images, they're not "get your project done" images.</i></b> Does your project require an mqtt client for example? That could be an issue, because the vendor wasn't benchmarking messaging performance, so the image doesn't include any mqtt client libraries.</p><p style="text-align: left;">"Here's the board, here's a link to download the image we've put together, and here's the press release highlighting our impressive achievements." <i><b>One thing these press releases will never highlight is that their impressive performance numbers were not achieved using upstream software. </b></i>The bootloader is most likely a fork, the kernel is almost certainly a fork, and any software they're benchmarking (and the system libraries upon which it depends) are often forks.</p><p style="text-align: left;">Does the manufacturer-provided image include all the libraries on top of which you need to build your software? Does it include all the services or daemons on which your software relies? Probably not, so now what do you do? How would you go about building additional software for your device the manufacturer doesn't include? Is there even an SDK? Even if one board does provide a library you need, would another board from a completely different manufacturer also provide that same library so you could run your project on both boards? And if both boards do provide that library, are they API-compatible, or do you need to write your software to support both an old and a new API of that library?</p><p style="text-align: left;">Increasingly in recent years, one popular way around the problem of how to develop additional software for different vendor-provided images that have different software stacks is to completely eschew compiled languages altogether! "Forget compilers, forget cross-development and all its challenges; that's way too difficult for you. We'll provide you with an interpreted language runtime, and you can script your way to project happiness. By the way, you're comfortable writing in Lua, right?". Another "solution" to this problem is to simply provide native compilers in the vendor-provided image so you can do your development work right on the target board itself. That's crazy! These solutions could work for very simple scenarios where the software only needs to do one simple task, but exciting projects need the ability to do real development.</p><p style="text-align: left;"><i><b>These types of problems (and more!) are solved with The Yocto Project.</b></i></p><p style="text-align: left;">The Yocto Project (colloquially: "Yocto") is a suite of tools to create your own embedded Linux distributions. You choose each and every piece of software you want included on your device. You choose whether you want sysvinit or systemd, X or Wayland, and so on. Then you choose the board you wish to target, and it builds your distribution/image for that board as well as all required dependencies. Perform the same build but target a different board (often a one-line change in your build configuration), and now you have the exact same software (versions and all) running on a completely different device. If you need to develop software for your product, Yocto will generate board-specific, image-specific SDKs for you, or you could use <span style="font-family: courier;">devtool</span> to build, upload, and generate test images as you write your code.</p><p style="text-align: left;">Of course there are some caveats. Not all combinations of all software work on every board. Sometimes a specific SoC does not have upstream support so you're forced to use vendor bootloaders and vendor kernels if you want anything to work. But the entire software stack above the kernel can be synchronized. This means that the list of packages installed into every board's image will not only be the same, but the versions will be the same as well. If your SoCs can run with the upstream kernel and bootloader, then the entire software stack can be synchronized amongst all your devices. The procedure to set the IP address on one board will work on all your boards. The tools and options you use to set a GPIO pin on one board will work on all your boards. Any software you write only needs to target one API, because all your boards are using those same libraries, and the same versions of all those libraries.</p><p style="text-align: left;">For my specific project I don't need any graphics and won't be using any display devices, so I start with a basic <span style="font-family: courier;">core-image-base</span>. Over the years I've collected together a set of tools and utilities I like to have on my images, so I include those. In this specific case I like when all my devices have their clocks synchronized so I'm going to install <span style="font-family: courier;">chrony</span> and configure all of them to point to my internal time server. I want them to know where they are, so I install a bunch of timezone packages (<span style="font-family: courier;">tzdata-core</span> and <span style="font-family: courier;">tzdata-posix</span>) and set the <span style="font-family: courier;">DEFAULT_TIMEZONE</span> to the one in which I live. I want all my devices to have an ssh server so I add that to my distribution, and because I'll be working with GPIOs in this project I also add <span style="font-family: courier;">libgpiod-tools</span>. Since power could be lost at any time and I want to minimize the possibility of corrupt root disks I also add <span style="font-family: courier;">read-only-rootfs</span> to my distro's <span style="font-family: courier;">EXTRA_IMAGE_FEATURES</span>. After that I start my builds for my various boards, test these base images, and they all work great. I'm ready to start writing the software that's going to give these boards the magic they need to make my project a reality!</p><p>For many embedded software teams, using a set of SBCs with no two of them the same in a project (or being is a situation where their chosen board goes EOL or becomes impossible to procure and a new board will need to be found) would be very challenging. Using a vendor-supplied image for anything other than the specific things the vendor wants to highlight is problematic. Also, each and every vendor-supplied image is different in significant ways from every other SBC's image. As a result hobbyists and professionals alike tend to use the same board/SoC everywhere for every project regardless of whether or not it's a good fit... and hope it will be available for a long time.</p><p>With Yocto, developing for several SBCs simultaneously is simple. Creating the same image for wildly different SoCs/boards and writing code for all of them simultaneously is how Yocto was designed to be used. Of course, if you want to use the same board everywhere, it also works great for that scenario as well. It brings conformity to your user experience regardless of underlying hardware. It provides you with the set of development tools you need to get your project done, and to maintain your project going forward.</p><p></p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-54056988552782997522023-01-18T23:31:00.000-05:002023-01-18T23:31:10.770-05:00Coordinated Holiday Lights - box 4<p style="text-align: left;">The forth box features the BeagleBone Black (bbb), the IoT Relay (I might as well use them since I already have them), and also has hard-wired ethernet. The bbb features TI's AM335x Sitara SoC which is based on a single-core, 32-bit, ARM, Cortex-A8. This device will control the lights on the eastern driveway gate.</p><p style="text-align: left;">Parts:<br /></p><ul style="text-align: left;"><li><a href="https://beagleboard.org/black" target="_blank">BeagleBone Black</a></li><li>Digital Loggers <a href="https://dlidirect.com/products/iot-power-relay" target="_blank">IoT Relay</a></li><li>Adafruit ethernet gland (product: <a href="https://www.adafruit.com/product/827" target="_blank">827</a>)</li><li>Wago <a href="https://www.wago.com/ca-en/electrical-interconnections/installation-terminal-blocks-and-connectors/221" target="_blank">221 connectors</a></li></ul><p style="text-align: left;">Unlike the RPi (or other RPi-like boards), the bbb is quite clear in its documentation that it can <i><b>not</b></i> be powered via its expansion pins. Therefore this build uses the 5V transformer that came with the board and plugs into the bbb's mini-B USB connector.</p><p style="text-align: left;">The bbb has both a soldered-on eMMC flash, and takes an SDcard. By default, if the firmware detects a valid image on the eMMC, its preference is to boot from that device over the SDcard. I want to always have my system boot from SDcard. Therefore on first boot I hold down the BOOT button in order to get it to boot from the SDcard and not the eMMC. Once running I then erased the eMMC flash. Without a valid image in eMMC the bbb's firmware will elect instead to boot from the SDcard.</p><p style="text-align: left;">On the one hand it's nice that so many SBCs have standardized around a common header. On the other hand it would have been nicer if the industry had standardized around a header that provided access to more of the buses and pins that projects could use. Of course in my case I only need access to 1 GPIO pin, therefore the standard "RPi 40-pin header" is more than adequate. However some projects can find the 40 pins of the RPi header limiting. If you find yourself in that sort of situation, you'll appreciate the bbb's staggering 92 pins:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://beagleboard.org/static/images/cape-headers.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="800" height="600" src="https://beagleboard.org/static/images/cape-headers.png" width="800" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p style="text-align: left;">Similar to the RPi, the bbb's kernel is well-loved, therefore the kernel knows a lot about its GPIOs:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #c65d09; font-weight: bold;">root@beaglebone:~#</span> gpioinfo
<span style="color: #888888;">gpiochip0 - 32 lines:</span>
<span style="color: #888888;"> line 0: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 1: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 2: "P9_22 [spi0_sclk]" unused input active-high </span>
<span style="color: #888888;"> line 3: "P9_21 [spi0_d0]" unused input active-high </span>
<span style="color: #888888;"> line 4: "P9_18 [spi0_d1]" unused input active-high </span>
<span style="color: #888888;"> line 5: "P9_17 [spi0_cs0]" unused input active-high </span>
<span style="color: #888888;"> line 6: "[sd card]" "cd" input active-low [used]</span>
<span style="color: #888888;"> line 7: "P9_42A [ecappwm0]" unused input active-high </span>
<span style="color: #888888;"> line 8: "P8_35 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 9: "P8_33 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 10: "P8_31 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 11: "P8_32 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 12: "P9_20 [i2c2_sda]" unused input active-high </span>
<span style="color: #888888;"> line 13: "P9_19 [i2c2_scl]" unused input active-high </span>
<span style="color: #888888;"> line 14: "P9_26 [uart1_rxd]" unused input active-high </span>
<span style="color: #888888;"> line 15: "P9_24 [uart1_txd]" unused input active-high </span>
<span style="color: #888888;"> line 16: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 17: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 18: "[usb]" unused input active-high </span>
<span style="color: #888888;"> line 19: "[hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 20: "P9_41B" unused input active-high </span>
<span style="color: #888888;"> line 21: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 22: "P8_19 [ehrpwm2a]" unused input active-high </span>
<span style="color: #888888;"> line 23: "P8_13 [ehrpwm2b]" unused input active-high </span>
<span style="color: #888888;"> line 24: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 25: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 26: "P8_14" unused input active-high </span>
<span style="color: #888888;"> line 27: "P8_17" unused input active-high </span>
<span style="color: #888888;"> line 28: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 29: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 30: "P9_11 [uart4_rxd]" unused input active-high </span>
<span style="color: #888888;"> line 31: "P9_13 [uart4_txd]" unused input active-high</span>
<span style="color: #888888;">gpiochip1 - 32 lines:</span>
<span style="color: #888888;"> line 0: "P8_25 [emmc]" unused input active-high </span>
<span style="color: #888888;"> line 1: "[emmc]" unused input active-high </span>
<span style="color: #888888;"> line 2: "P8_5 [emmc]" unused input active-high </span>
<span style="color: #888888;"> line 3: "P8_6 [emmc]" unused input active-high </span>
<span style="color: #888888;"> line 4: "P8_23 [emmc]" unused input active-high </span>
<span style="color: #888888;"> line 5: "P8_22 [emmc]" unused input active-high </span>
<span style="color: #888888;"> line 6: "P8_3 [emmc]" unused input active-high </span>
<span style="color: #888888;"> line 7: "P8_4 [emmc]" unused input active-high </span>
<span style="color: #888888;"> line 8: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 9: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 10: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 11: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 12: "P8_12" unused input active-high </span>
<span style="color: #888888;"> line 13: "P8_11" unused input active-high </span>
<span style="color: #888888;"> line 14: "P8_16" unused input active-high </span>
<span style="color: #888888;"> line 15: "P8_15" unused input active-high </span>
<span style="color: #888888;"> line 16: "P9_15A" unused input active-high </span>
<span style="color: #888888;"> line 17: "P9_23" unused input active-high </span>
<span style="color: #888888;"> line 18: "P9_14 [ehrpwm1a]" unused input active-high </span>
<span style="color: #888888;"> line 19: "P9_16 [ehrpwm1b]" unused input active-high </span>
<span style="color: #888888;"> line 20: "[emmc]" unused input active-high </span>
<span style="color: #888888;"> line 21: "[usr0 led]" "beaglebone:green:heartbeat" output active-high [used]</span>
<span style="color: #888888;"> line 22: "[usr1 led]" "beaglebone:green:mmc0" output active-high [used]</span>
<span style="color: #888888;"> line 23: "[usr2 led]" "beaglebone:green:usr2" output active-high [used]</span>
<span style="color: #888888;"> line 24: "[usr3 led]" "beaglebone:green:usr3" output active-high [used]</span>
<span style="color: #888888;"> line 25: "[hdmi]" "interrupt" input active-high [used]</span>
<span style="color: #888888;"> line 26: "[usb]" unused input active-high </span>
<span style="color: #888888;"> line 27: "[hdmi audio]" "enable" output active-high [used]</span>
<span style="color: #888888;"> line 28: "P9_12" unused input active-high </span>
<span style="color: #888888;"> line 29: "P8_26" unused input active-high </span>
<span style="color: #888888;"> line 30: "P8_21 [emmc]" unused input active-high </span>
<span style="color: #888888;"> line 31: "P8_20 [emmc]" unused input active-high </span>
<span style="color: #888888;">gpiochip2 - 32 lines:</span>
<span style="color: #888888;"> line 0: "P9_15B" unused input active-high </span>
<span style="color: #888888;"> line 1: "P8_18" unused input active-high </span>
<span style="color: #888888;"> line 2: "P8_7" unused input active-high </span>
<span style="color: #888888;"> line 3: "P8_8" unused input active-high </span>
<span style="color: #888888;"> line 4: "P8_10" unused input active-high </span>
<span style="color: #888888;"> line 5: "P8_9" unused input active-high </span>
<span style="color: #888888;"> line 6: "P8_45 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 7: "P8_46 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 8: "P8_43 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 9: "P8_44 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 10: "P8_41 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 11: "P8_42 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 12: "P8_39 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 13: "P8_40 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 14: "P8_37 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 15: "P8_38 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 16: "P8_36 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 17: "P8_34 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 18: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 19: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 20: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 21: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 22: "P8_27 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 23: "P8_29 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 24: "P8_28 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 25: "P8_30 [hdmi]" unused input active-high </span>
<span style="color: #888888;"> line 26: "[emmc]" unused input active-high </span>
<span style="color: #888888;"> line 27: "[emmc]" unused input active-high </span>
<span style="color: #888888;"> line 28: "[emmc]" unused input active-high </span>
<span style="color: #888888;"> line 29: "[emmc]" unused input active-high </span>
<span style="color: #888888;"> line 30: "[emmc]" unused input active-high </span>
<span style="color: #888888;"> line 31: "[emmc]" unused input active-high</span>
<span style="color: #888888;">gpiochip3 - 32 lines:</span>
<span style="color: #888888;"> line 0: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 1: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 2: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 3: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 4: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 5: "[i2c0]" unused input active-high </span>
<span style="color: #888888;"> line 6: "[i2c0]" unused input active-high </span>
<span style="color: #888888;"> line 7: "[emu]" unused input active-high </span>
<span style="color: #888888;"> line 8: "[emu]" unused input active-high </span>
<span style="color: #888888;"> line 9: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 10: "[ethernet]" unused input active-high </span>
<span style="color: #888888;"> line 11: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 12: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 13: "[usb]" unused input active-high </span>
<span style="color: #888888;"> line 14: "P9_31 [spi1_sclk]" unused input active-high </span>
<span style="color: #888888;"> line 15: "P9_29 [spi1_d0]" unused input active-high </span>
<span style="color: #888888;"> line 16: "P9_30 [spi1_d1]" unused input active-high </span>
<span style="color: #888888;"> line 17: "P9_28 [spi1_cs0]" unused input active-high </span>
<span style="color: #888888;"> line 18: "P9_42B [ecappwm0]" unused input active-high </span>
<span style="color: #888888;"> line 19: "P9_27" unused input active-high </span>
<span style="color: #888888;"> line 20: "P9_41A" unused input active-high </span>
<span style="color: #888888;"> line 21: "P9_25" unused input active-high </span>
<span style="color: #888888;"> line 22: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 23: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 24: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 25: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 26: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 27: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 28: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 29: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 30: "[NC]" unused input active-high </span>
<span style="color: #888888;"> line 31: "[NC]" unused input active-high</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Arbitrarily, I've decided that I'm going to use GPIO_45. GPIO_45 is located on connector P8, pin 11. Looking through the information provided above we see that <span style="font-family: courier;">P8_11</span> is found at gpiochip1, line 13. No datasheets, schematics, or reference manuals required! Wiring up a prototype, we can perform the following quick test:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #c65d09; font-weight: bold;">root@raspberrypi3-64:~#</span> gpioset gpiochip1 <span style="color: #996633;">13</span><span style="color: #333333;">=</span><span style="color: #6600ee; font-weight: bold;">1</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Wait a minute! The load didn't turn on, why aren't the lights on after running the above command?</p><p style="text-align: left;">At first I assumed I had done something wrong: bad wiring or maybe bad GPIO? I checked all the wiring; looks okay. Then I tried a different GPIO; same result. Maybe try a GPIO on the P9 connnector; still doesn't work. One of the times I ran the gpioset program I did hear the relay click, although the lights didn't turn on, which led me to believe I had found the correct GPIO/pin association. After a bit of searching around I came across the <span style="font-family: courier;">--mode=wait</span> option of <span style="font-family: courier;">gpioset</span>.</p><p style="text-align: left;">As long as the <span style="font-family: courier;">gpioset</span> program is running, it will control the GPIO line, but when it terminates, it releases the line. Coincidentally, on all the other SBCs I've used so far, after <span style="font-family: courier;">gpioset</span> terminates, the line stays where it had been set. As a result the lights are turned on and stay on. On the bbb, however, after the <span style="font-family: courier;">gpioset</span> program terminates the GPIO line doesn't continue on in the state in which it was set, rather it returns to its previous "OFF" state. Since code is fast and relays are slow, most times the relay doesn't even click over (never mind the lights coming on) before the relay is de-activated. Therefore when testing gpio lines with gpioset, it would be best to test with the following and then terminate the program with <span style="font-family: courier;">Ctrl-C</span>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #c65d09; font-weight: bold;">root@raspberrypi3-64:~#</span> gpioset --mode<span style="color: #333333;">=</span><span style="color: #007020;">wait</span> gpiochip1 <span style="color: #996633;">13</span><span style="color: #333333;">=</span><span style="color: #6600ee; font-weight: bold;">1</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;"><br /></p>
<p style="text-align: left;">fritzing:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2cRwhiB9F9N-Pbiy3Afmt2lImgd8hh1PBclGE5QyOCFP7uJMrFQhmdSDWDQ6p1MkDvTpPxTmmwuOXWg-hy0oUdYjqEsA4Z40CRPc7rLE3SQh_Cv4ge_RrtiqjVtSZuVYYLiIFfcWtCUFr4oC431Qs1UkvViBHwDPUoyuhATNhgbwCKPHSHeA0eDyx/s3600/box4_bb.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2505" data-original-width="3600" height="445" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2cRwhiB9F9N-Pbiy3Afmt2lImgd8hh1PBclGE5QyOCFP7uJMrFQhmdSDWDQ6p1MkDvTpPxTmmwuOXWg-hy0oUdYjqEsA4Z40CRPc7rLE3SQh_Cv4ge_RrtiqjVtSZuVYYLiIFfcWtCUFr4oC431Qs1UkvViBHwDPUoyuhATNhgbwCKPHSHeA0eDyx/w640-h445/box4_bb.png" width="640" /></a></div><br /><p style="text-align: left;"><br /></p><p style="text-align: left;">finished box:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWCdWkdW5ZdcRhNw55f8v7eqskCrvtg28V6QJUpIHmnFEthpIgkwOLaJp7uCNMjai7nsftz35sY8J4ESEsvnUE6NTuuc7USINqxBgo1ohJ_HTUe3P19lcK0oYV5S-8f2vwmMBiuOm1buHUW71Jn2TASk9lqiSgJO84Loy9fRFVPt6OePeEpPvSQLol/s512/box-bbb.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWCdWkdW5ZdcRhNw55f8v7eqskCrvtg28V6QJUpIHmnFEthpIgkwOLaJp7uCNMjai7nsftz35sY8J4ESEsvnUE6NTuuc7USINqxBgo1ohJ_HTUe3P19lcK0oYV5S-8f2vwmMBiuOm1buHUW71Jn2TASk9lqiSgJO84Loy9fRFVPt6OePeEpPvSQLol/s16000/box-bbb.jpg" /></a></div><br /><p style="text-align: left;"><br /></p><p style="text-align: left;">before install:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJCe-U2N5jjVx6wo97uh684YYLsWG5yaEFN511SgSvTvbdoboBhyjL52sREawyF0N6NSNydQPABBgrxcvqpYA6Q33REJ8DYTzjSm4kE0YOHvvR2bLWuBgaZVV2N6rfRsJhZsyYnC7hFvlNhSS9pXY_bGYenwBM8GPWTzkq3k2n40Y99ns8o8rYSiW4/s384/box-bbb-install-before.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJCe-U2N5jjVx6wo97uh684YYLsWG5yaEFN511SgSvTvbdoboBhyjL52sREawyF0N6NSNydQPABBgrxcvqpYA6Q33REJ8DYTzjSm4kE0YOHvvR2bLWuBgaZVV2N6rfRsJhZsyYnC7hFvlNhSS9pXY_bGYenwBM8GPWTzkq3k2n40Y99ns8o8rYSiW4/s16000/box-bbb-install-before.jpg" /></a></div><br /><p style="text-align: left;"><br /></p><p style="text-align: left;">after install:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSaJWGL_zwOA3i1iovNi5sNkEeXxQ9L-uiGXie6rKGNm7KVI45XNecl9M-57hzJ2cTV_7ud_ueQ6W_tsmqq5xyvSok2GAINsoPztJV15F8qNyGHrQT5mMmmUVpPqETCqA-xpW0GLI43xfcT0MoKpHSTV1la5Jhr_LNVu-svdnsKK1Q4Fl5-JCSjbyt/s512/box-bbb-install-done.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSaJWGL_zwOA3i1iovNi5sNkEeXxQ9L-uiGXie6rKGNm7KVI45XNecl9M-57hzJ2cTV_7ud_ueQ6W_tsmqq5xyvSok2GAINsoPztJV15F8qNyGHrQT5mMmmUVpPqETCqA-xpW0GLI43xfcT0MoKpHSTV1la5Jhr_LNVu-svdnsKK1Q4Fl5-JCSjbyt/s16000/box-bbb-install-done.jpg" /></a></div><br /><p style="text-align: left;"><br /></p><p style="text-align: left;"><br /></p><p></p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-2934256420006329122023-01-16T22:48:00.001-05:002023-01-16T23:21:47.891-05:00Coordinated Holiday Lights - box 3<p style="text-align: left;">The third box that I put together has the rock-pi-e SBC, uses the IoT Relay from Digital Loggers, and has ethernet wired to its location. The rock-pi-e features the Rockchip rk3328 which is a quad-core, 64-bit, ARM Cortex-A53 SoC. I intend to use this device to power the lights on the western driveway gate.</p><p style="text-align: left;">Parts:<br /></p><ul style="text-align: left;"><li>Radxa <a href="https://wiki.radxa.com/RockpiE" target="_blank">ROCK Pi E</a></li><li>Digital Loggers <a href="https://dlidirect.com/products/iot-power-relay" target="_blank">IoT Relay</a></li><li>Adafruit ethernet gland (product: <a href="https://www.adafruit.com/product/827" target="_blank">827</a>)</li><li>Wago <a href="https://www.wago.com/ca-en/electrical-interconnections/installation-terminal-blocks-and-connectors/221" target="_blank">221 connectors</a></li><li>Mean Well <a href="https://www.meanwell-web.com/en-gb/ac-dc-single-output-enclosed-power-supply-output-rs--15--5" target="_blank">RS-15-5</a> switching power supply</li></ul><p></p><p style="text-align: left;">Having wired ethernet to this (or any) location is a huge improvement over WiFi or ethernet-over-power (i.e. powerline) schemes. Running ethernet isn't cheap, but I believe it's worth it. That being the case, this box doesn't need a powerline adapter, but it does need a weatherproof gland for ethernet. As is the issue with plugs and outlets, trying to find a gland that can open large enough to accomodate the RJ-45 ethernet jack to pass through, but that also close down enough to seal the cable are hard to find. The ideal solution is the cut the ethernet cable, pass it through a gland, then clamp the connector on afterwards. Maybe someday I'll be forced to create my own ethernet cables (and at that point I'll wonder why I ever did it any other way!) but for today Adafruit comes to the rescue with these intelligent and easy to use ethernet glands. The cable on the outside plugs into the gland on one side, and on the inside of the box is another connector for a short cable to run from the gland to the SBC.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_dQIRgzdx3Z9J8Zuu6omt9TJ79gRJO1a7FnjuwO7zdmpbJ7S5BzC1vTKNQuFeQCev1aKiE-tKOXP8BeA7DWOyxxCXvfHnvJ6IOUhFgRx6S-LOMdl_EtoYeiWsbnm5himxsvBe77uJiVU8RGNEfzHWzf7R4VpjNvgOo1V-5l-apa-vq7qbIxOAR8wl/s970/adafruit-827-06.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="728" data-original-width="970" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_dQIRgzdx3Z9J8Zuu6omt9TJ79gRJO1a7FnjuwO7zdmpbJ7S5BzC1vTKNQuFeQCev1aKiE-tKOXP8BeA7DWOyxxCXvfHnvJ6IOUhFgRx6S-LOMdl_EtoYeiWsbnm5himxsvBe77uJiVU8RGNEfzHWzf7R4VpjNvgOo1V-5l-apa-vq7qbIxOAR8wl/s320/adafruit-827-06.jpg" width="320" /></a></div><br /><p style="text-align: left;">The rest of the box construction is pretty straight-forward. Comments that I have regarding the IoT Relay, the power supply, and the Wago connectors are covered in other posts in this series. As with the Raspberry Pi 3, this device can also be powered through its GPIO pins. Similar to the imx233-olinuxino-maxi, the rock-pi-e also does not have factory-provided MAC addresses, but this is easily remedied.</p><p style="text-align: left;">This SoC seems to have the same fate as the older i.MX233 device despite being much more modern. It doesn't look like anyone has gotten around to associating this board's GPIO pins with their names:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #c65d09; font-weight: bold;">root@rock-pi-e:~#</span> gpioinfo
<span style="color: #888888;">gpiochip0 - 32 lines:</span>
<span style="color: #888888;"> line 0: unnamed "vcc-wifi-regulator" output active-low [used]</span>
<span style="color: #888888;"> line 1: unnamed unused input active-high </span>
<span style="color: #888888;"> line 2: unnamed unused input active-high </span>
<span style="color: #888888;"> line 3: unnamed unused input active-high </span>
<span style="color: #888888;"> line 4: unnamed unused input active-high </span>
<span style="color: #888888;"> line 5: unnamed unused input active-high </span>
<span style="color: #888888;"> line 6: unnamed unused input active-high </span>
<span style="color: #888888;"> line 7: unnamed unused input active-high </span>
<span style="color: #888888;"> line 8: unnamed unused input active-high </span>
<span style="color: #888888;"> line 9: unnamed unused input active-high </span>
<span style="color: #888888;"> line 10: unnamed unused input active-high </span>
<span style="color: #888888;"> line 11: unnamed unused input active-high </span>
<span style="color: #888888;"> line 12: unnamed unused input active-high </span>
<span style="color: #888888;"> line 13: unnamed unused input active-high </span>
<span style="color: #888888;"> line 14: unnamed unused input active-high </span>
<span style="color: #888888;"> line 15: unnamed unused input active-high </span>
<span style="color: #888888;"> line 16: unnamed unused input active-high </span>
<span style="color: #888888;"> line 17: unnamed unused input active-high </span>
<span style="color: #888888;"> line 18: unnamed unused input active-high </span>
<span style="color: #888888;"> line 19: unnamed unused input active-high </span>
<span style="color: #888888;"> line 20: unnamed unused input active-high </span>
<span style="color: #888888;"> line 21: unnamed unused input active-high </span>
<span style="color: #888888;"> line 22: unnamed unused input active-high </span>
<span style="color: #888888;"> line 23: unnamed unused input active-high </span>
<span style="color: #888888;"> line 24: unnamed unused input active-high </span>
<span style="color: #888888;"> line 25: unnamed unused input active-high </span>
<span style="color: #888888;"> line 26: unnamed unused input active-high </span>
<span style="color: #888888;"> line 27: unnamed unused input active-high </span>
<span style="color: #888888;"> line 28: unnamed unused input active-high </span>
<span style="color: #888888;"> line 29: unnamed unused input active-high </span>
<span style="color: #888888;"> line 30: unnamed "sdmmc-regulator" output active-low [used]</span>
<span style="color: #888888;"> line 31: unnamed unused input active-high</span>
<span style="color: #888888;">gpiochip1 - 32 lines:</span>
<span style="color: #888888;"> line 0: unnamed unused input active-high </span>
<span style="color: #888888;"> line 1: unnamed unused input active-high </span>
<span style="color: #888888;"> line 2: unnamed unused input active-high </span>
<span style="color: #888888;"> line 3: unnamed unused input active-high </span>
<span style="color: #888888;"> line 4: unnamed unused input active-high </span>
<span style="color: #888888;"> line 5: unnamed unused input active-high </span>
<span style="color: #888888;"> line 6: unnamed unused input active-high </span>
<span style="color: #888888;"> line 7: unnamed unused input active-high </span>
<span style="color: #888888;"> line 8: unnamed unused input active-high </span>
<span style="color: #888888;"> line 9: unnamed unused input active-high </span>
<span style="color: #888888;"> line 10: unnamed unused input active-high </span>
<span style="color: #888888;"> line 11: unnamed unused input active-high </span>
<span style="color: #888888;"> line 12: unnamed unused input active-high </span>
<span style="color: #888888;"> line 13: unnamed unused input active-high </span>
<span style="color: #888888;"> line 14: unnamed unused input active-high </span>
<span style="color: #888888;"> line 15: unnamed unused input active-high </span>
<span style="color: #888888;"> line 16: unnamed unused input active-high </span>
<span style="color: #888888;"> line 17: unnamed unused input active-high </span>
<span style="color: #888888;"> line 18: unnamed unused input active-high </span>
<span style="color: #888888;"> line 19: unnamed unused input active-high </span>
<span style="color: #888888;"> line 20: unnamed unused input active-high </span>
<span style="color: #888888;"> line 21: unnamed unused input active-high </span>
<span style="color: #888888;"> line 22: unnamed unused input active-high </span>
<span style="color: #888888;"> line 23: unnamed unused input active-high </span>
<span style="color: #888888;"> line 24: unnamed unused input active-high </span>
<span style="color: #888888;"> line 25: unnamed unused input active-high </span>
<span style="color: #888888;"> line 26: unnamed unused input active-high </span>
<span style="color: #888888;"> line 27: unnamed unused input active-high </span>
<span style="color: #888888;"> line 28: unnamed unused input active-high </span>
<span style="color: #888888;"> line 29: unnamed unused input active-high </span>
<span style="color: #888888;"> line 30: unnamed unused input active-high </span>
<span style="color: #888888;"> line 31: unnamed unused input active-high </span>
<span style="color: #888888;">gpiochip2 - 32 lines:</span>
<span style="color: #888888;"> line 0: unnamed unused input active-high </span>
<span style="color: #888888;"> line 1: unnamed unused input active-high </span>
<span style="color: #888888;"> line 2: unnamed unused input active-high </span>
<span style="color: #888888;"> line 3: unnamed unused output active-high </span>
<span style="color: #888888;"> line 4: unnamed unused input active-high </span>
<span style="color: #888888;"> line 5: unnamed unused input active-high </span>
<span style="color: #888888;"> line 6: unnamed "interrupt" input active-high [used]</span>
<span style="color: #888888;"> line 7: unnamed unused input active-high </span>
<span style="color: #888888;"> line 8: unnamed unused input active-high </span>
<span style="color: #888888;"> line 9: unnamed unused input active-high </span>
<span style="color: #888888;"> line 10: unnamed unused input active-high </span>
<span style="color: #888888;"> line 11: unnamed unused input active-high </span>
<span style="color: #888888;"> line 12: unnamed unused input active-high </span>
<span style="color: #888888;"> line 13: unnamed unused input active-high </span>
<span style="color: #888888;"> line 14: unnamed unused input active-high </span>
<span style="color: #888888;"> line 15: unnamed unused input active-high </span>
<span style="color: #888888;"> line 16: unnamed unused input active-high </span>
<span style="color: #888888;"> line 17: unnamed unused input active-high </span>
<span style="color: #888888;"> line 18: unnamed unused input active-high </span>
<span style="color: #888888;"> line 19: unnamed unused input active-high </span>
<span style="color: #888888;"> line 20: unnamed unused input active-high </span>
<span style="color: #888888;"> line 21: unnamed unused input active-high </span>
<span style="color: #888888;"> line 22: unnamed unused input active-high </span>
<span style="color: #888888;"> line 23: unnamed unused input active-high</span>
<span style="color: #888888;"> line 24: unnamed unused input active-high </span>
<span style="color: #888888;"> line 25: unnamed unused input active-high </span>
<span style="color: #888888;"> line 26: unnamed unused input active-high </span>
<span style="color: #888888;"> line 27: unnamed unused input active-high </span>
<span style="color: #888888;"> line 28: unnamed unused input active-high </span>
<span style="color: #888888;"> line 29: unnamed unused input active-high </span>
<span style="color: #888888;"> line 30: unnamed unused input active-high </span>
<span style="color: #888888;"> line 31: unnamed unused input active-high</span>
<span style="color: #888888;">gpiochip3 - 32 lines:</span>
<span style="color: #888888;"> line 0: unnamed unused input active-high </span>
<span style="color: #888888;"> line 1: unnamed unused input active-high </span>
<span style="color: #888888;"> line 2: unnamed unused input active-high </span>
<span style="color: #888888;"> line 3: unnamed unused input active-high </span>
<span style="color: #888888;"> line 4: unnamed unused input active-high </span>
<span style="color: #888888;"> line 5: unnamed "blue:" output active-low [used]</span>
<span style="color: #888888;"> line 6: unnamed unused input active-high </span>
<span style="color: #888888;"> line 7: unnamed "vcc-host-5v-regulator" output active-high [used]</span>
<span style="color: #888888;"> line 8: unnamed unused input active-high </span>
<span style="color: #888888;"> line 9: unnamed unused input active-high </span>
<span style="color: #888888;"> line 10: unnamed unused input active-high </span>
<span style="color: #888888;"> line 11: unnamed unused input active-high </span>
<span style="color: #888888;"> line 12: unnamed unused input active-high </span>
<span style="color: #888888;"> line 13: unnamed unused input active-high </span>
<span style="color: #888888;"> line 14: unnamed unused input active-high </span>
<span style="color: #888888;"> line 15: unnamed unused input active-high </span>
<span style="color: #888888;"> line 16: unnamed unused input active-high </span>
<span style="color: #888888;"> line 17: unnamed unused input active-high </span>
<span style="color: #888888;"> line 18: unnamed unused input active-high </span>
<span style="color: #888888;"> line 19: unnamed unused input active-high </span>
<span style="color: #888888;"> line 20: unnamed unused input active-high </span>
<span style="color: #888888;"> line 21: unnamed unused input active-high </span>
<span style="color: #888888;"> line 22: unnamed unused input active-high </span>
<span style="color: #888888;"> line 23: unnamed unused input active-high </span>
<span style="color: #888888;"> line 24: unnamed unused input active-high </span>
<span style="color: #888888;"> line 25: unnamed unused input active-high </span>
<span style="color: #888888;"> line 26: unnamed unused input active-high </span>
<span style="color: #888888;"> line 27: unnamed unused input active-high </span>
<span style="color: #888888;"> line 28: unnamed unused input active-high </span>
<span style="color: #888888;"> line 29: unnamed unused input active-high </span>
<span style="color: #888888;"> line 30: unnamed unused input active-high </span>
<span style="color: #888888;"> line 31: unnamed unused input active-high</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Thankfully the <a href="https://wiki.radxa.com/RockpiE/hardware/gpio" target="_blank">Radxa Wiki page on this SoC's GPIOs</a> provides all the information we need without having to dive into schematics and reference manuals. Simply locate the pin you want to use, then run the various values through the equation they provide and you're done. As with the Raspberry Pi 3, I've decided to use pin 40 for the relay signal. Since I'm using a V1.2 rock-pi-e board I consult the drawing for V1.2:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWLU9Igg2acYD7gQnkuU-_o4fdY3mGpB8bEsAwRck5OyMlPMmecyJc5FEWpsUkxvLN_WbsN1JdUpRC6vpUbqoqskhPdsNuLgeKZ_2olwvDsN0G_oPwUkJXVCHHouKj2LrKCKjgdk_QWrFbM_OJbSOW_xxQL6t8DGv04qQnEVLt7qZkS_4N6C7reb1h/s954/rock-pi-e-gpio.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="724" data-original-width="954" height="486" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWLU9Igg2acYD7gQnkuU-_o4fdY3mGpB8bEsAwRck5OyMlPMmecyJc5FEWpsUkxvLN_WbsN1JdUpRC6vpUbqoqskhPdsNuLgeKZ_2olwvDsN0G_oPwUkJXVCHHouKj2LrKCKjgdk_QWrFbM_OJbSOW_xxQL6t8DGv04qQnEVLt7qZkS_4N6C7reb1h/w640-h486/rock-pi-e-gpio.png" width="640" /></a></div><br /><p style="text-align: left;">Pin 40 is known as GPIO2_C7. The format of the naming is as follows:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOnvRnIQm0OT4vYajLVZldLeBqPfswGEnt32C6r-MjdckIi_pHrJdU3IooflY6cDr54yRO2iwLbIXZH3Gl-7mXC2XOKJiiTHCR8Nch_P36eTEppEKUTYPxSOrRU1XD3vd_EfmOn2o4EyE45ESLIIAhTmJrVUoDX63pgIFZIKG9-hTOxn34GqvKhBwy/s295/rockpie-gpio-calc.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="292" data-original-width="295" height="292" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOnvRnIQm0OT4vYajLVZldLeBqPfswGEnt32C6r-MjdckIi_pHrJdU3IooflY6cDr54yRO2iwLbIXZH3Gl-7mXC2XOKJiiTHCR8Nch_P36eTEppEKUTYPxSOrRU1XD3vd_EfmOn2o4EyE45ESLIIAhTmJrVUoDX63pgIFZIKG9-hTOxn34GqvKhBwy/s1600/rockpie-gpio-calc.png" width="295" /></a></div><p style="text-align: left;">Therefore GPIO2_C7 tells us that the pin is on gpiochip2, pin 8*2 + 7 = 23.</p><p style="text-align: left;">Fritzing:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMHcqKT08svt7ZioOXyzT8ULQMlKNq-0qBjt7MPo7BfgKczRBzV2XkEgWzo88gXiXSds_CkcfRLvjLhu2akIqYPOSqRRXDcKpVRrlWongsRnO6p-9nCg7xzsbHlqu-sEX_NDtmsQ7K6rjOFwQh5RhMraBgHJbjk0BB1lWzzAW9ZO6voAWpgnGIZhan/s3669/box3_bb.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2748" data-original-width="3669" height="479" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMHcqKT08svt7ZioOXyzT8ULQMlKNq-0qBjt7MPo7BfgKczRBzV2XkEgWzo88gXiXSds_CkcfRLvjLhu2akIqYPOSqRRXDcKpVRrlWongsRnO6p-9nCg7xzsbHlqu-sEX_NDtmsQ7K6rjOFwQh5RhMraBgHJbjk0BB1lWzzAW9ZO6voAWpgnGIZhan/w640-h479/box3_bb.png" width="640" /></a></div><br /><p style="text-align: left;">Here's how the finished box looks:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1k5CvqpE5DQ_YoKbalOBv7xtOyZfQOMrmuoHUCq2exWby_G8OLVuRZLB_W6AlYW7uVCPgw15rIZWRloJNi0dNHgqQsJXvy4QbwnSonzqn5GVTVugRrOJLpmhsK6isj7d0E7U9DC7GNjxDvQ4q0COqAdGmx8FUKZFV6s7J6SZQBCoVTzFPLiPOew1p/s512/box-rockpie.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1k5CvqpE5DQ_YoKbalOBv7xtOyZfQOMrmuoHUCq2exWby_G8OLVuRZLB_W6AlYW7uVCPgw15rIZWRloJNi0dNHgqQsJXvy4QbwnSonzqn5GVTVugRrOJLpmhsK6isj7d0E7U9DC7GNjxDvQ4q0COqAdGmx8FUKZFV6s7J6SZQBCoVTzFPLiPOew1p/s16000/box-rockpie.jpg" /></a></div><br /><p style="text-align: left;"><br /></p><p style="text-align: left;">Before installation:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgc_iTHbmq_9iWZ2joG5Xh9bwxm0rIkqllxHDULyEMatJ0bX0Wi8jN-dWd5Eu95s6oC6Bas-TEgYCqxPdp93JkXsOPm6sgAveXEahP2zuwEAzxdAO0uwTMQajgWd2jkHelRTyqYm120HDtSvEj3NehkJacwVA2z8yuIZT_JwlFQWlJjlQrFop3wcoan/s512/box-rockpie-install-before.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="231" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgc_iTHbmq_9iWZ2joG5Xh9bwxm0rIkqllxHDULyEMatJ0bX0Wi8jN-dWd5Eu95s6oC6Bas-TEgYCqxPdp93JkXsOPm6sgAveXEahP2zuwEAzxdAO0uwTMQajgWd2jkHelRTyqYm120HDtSvEj3NehkJacwVA2z8yuIZT_JwlFQWlJjlQrFop3wcoan/s16000/box-rockpie-install-before.jpg" /></a></div><br /><p style="text-align: left;"><br /></p><p style="text-align: left;">After installation:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_hxBDGguMYk4NuCxDPPZ7vm8TXsXdiBjyPgCTgCmOd1wouo526QJpng-MvVEIm28EoKjOpJiqtGiujUxxpHHiYzHiDfuWclC1RBo-g8MOMReuWCQLxOV7ORE4oRYoFaFhADN5rBIQjyHRdY2XruVYWvREaIvuD0ykphwQzbqSFjttaLMgrze4IQLn/s512/box-rockpie-install-done.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="375" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_hxBDGguMYk4NuCxDPPZ7vm8TXsXdiBjyPgCTgCmOd1wouo526QJpng-MvVEIm28EoKjOpJiqtGiujUxxpHHiYzHiDfuWclC1RBo-g8MOMReuWCQLxOV7ORE4oRYoFaFhADN5rBIQjyHRdY2XruVYWvREaIvuD0ykphwQzbqSFjttaLMgrze4IQLn/s16000/box-rockpie-install-done.jpg" /></a></div><br /><p style="text-align: left;"><br /></p><p style="text-align: left;"><br /></p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-31054916271234329502023-01-16T07:38:00.001-05:002023-01-16T22:43:32.237-05:00Coordinated Holiday Lights - box 2<p>The second box that I put together features an Olimex iMX233-OlinuXino-MAXI for the SBC, connects to the network via an ethernet-over-power device, and uses a Digital Loggers "IoT Relay" device. The MAXI features the i.MX233 SoC which has a 32-bit, ARM9 arm926ej-s at its core. My intention is to use this device to run the lights on the bush in front of the house.</p><p>Parts:</p><p></p><ul style="text-align: left;"><li>Olimex <a href="https://www.olimex.com/Products/OLinuXino/iMX233/iMX233-OLinuXino-MAXI/open-source-hardware" target="_blank">iMX233-OlinuXino-MAXI</a></li><li>Digital Loggers <a href="https://dlidirect.com/products/iot-power-relay" target="_blank">IoT Relay</a></li><li>Wago <a href="https://www.wago.com/ca-en/electrical-interconnections/installation-terminal-blocks-and-connectors/221" target="_blank">221 connectors</a></li><li>TP-Link <a href="https://www.tp-link.com/ca/home-networking/powerline/tl-pa7017-kit/" target="_blank">AV1000</a> powerline adapter</li><li>NEMA 5-15P/C13 <a href="http://www.economik.com/hosa/pwd-402/" target="_blank">piggy-back</a> power cord</li></ul><p style="text-align: left;">When I was first thinking of this project (a couple years ago), I thought the "IoT Relay" from Digital Loggers would be a good device around-which to create my design. I was hoping it would keep me from having to do a lot of cutting and splicing of mains power cables. However, in order to get cables into and out of the box, cutting and splicing is unavoidable. So while these are neat devices, and I did end up using a couple of them (I had already bought them for this project), they're a little over-kill. Simple relays (as in box 1) would be more than adequate, and would save a bunch of space. Nevertheless, the IoT Relay has 4 NEMA 5-15P outlets: 3 of which are controlled by the control signal, 1 of which is "always on" (provided the device itself has power and is switched on). 2 of the 3 controlled outlets are "normally OFF" and the 3rd outlet is "normally ON". A removable screw terminal provides the signal by which to control the relay.</p><p style="text-align: left;">To supply power for the MAXI, I simply plugged the 12V 1A wall wart that came with the board into the IoT Relay's "Always ON" outlet.</p><p style="text-align: left;">The piggy-back NEMA 5-15P to C13 do-hicky was quite a lucky find! The IoT Relay has a C14 connector, and I needed a second 5-15P for the powerline adapter, so this device was able to solve both problems.</p><p style="text-align: left;">One small thing that tripped me up momentarily when working with the MAXI is that it doesn't have a manufacturer-assigned, static MAC address. I noticed this while setting up and testing my DHCP configuration, this board kept being assigned an IP address from the DHCP pool instead of the static IP I wanted it to have. Fortunately setting up a static, user-defined, <a href="https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local_(U/L_bit)" target="_blank">locally-administered, unicast</a>, MAC address <a href="https://github.com/twoerner/oe-misc/blob/master/notes#L73" target="_blank">isn't too difficult</a> if it only needs to be set when Linux runs (if you need your bootloader to know/setup the MAC address, then other arrangements need to be made).</p><p style="text-align: left;">The iMX233-OlinuXino-MAXI is designed around the Freescale (now NXP) i.MX233 SoC. This SoC has an arm926ej-s at its core. The arm926ej-s was introduced in 2001; the i.MX233 SoC was brought to market in 2009. Despite its age, this SoC is still being produced, and Olimex is still building and selling boards around this device. Unfortunately, being an older device, its Linux kernel support isn't up to par. One of the issues is due to the fact it is so old, meaning it receives less active development. When it was introduced and support was added for it in the Linux kernel, the kernel had a completely different GPIO subsystem. In the intervening years that subsystem has been entirely re-written. All the newer, more popular, regularly-used SoCs all had their GPIO subsystems well integrated with the new subsystem. Older SoCs compile, but that's about it. As a result the kernel's GPIO information is rather lacking:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #c65d09; font-weight: bold;">root@imx233-olinuxino-maxi:~#</span> gpioinfo
<span style="color: #888888;">gpiochip0 - 32 lines:</span>
<span style="color: #888888;"> line 0: unnamed unused input active-high </span>
<span style="color: #888888;"> line 1: unnamed unused input active-high </span>
<span style="color: #888888;"> line 2: unnamed unused input active-high </span>
<span style="color: #888888;"> line 3: unnamed unused input active-high </span>
<span style="color: #888888;"> line 4: unnamed unused input active-high </span>
<span style="color: #888888;"> line 5: unnamed unused input active-high </span>
<span style="color: #888888;"> line 6: unnamed unused input active-high </span>
<span style="color: #888888;"> line 7: unnamed unused input active-high </span>
<span style="color: #888888;"> line 8: unnamed unused input active-high </span>
<span style="color: #888888;"> line 9: unnamed unused input active-high </span>
<span style="color: #888888;"> line 10: unnamed unused input active-high </span>
<span style="color: #888888;"> line 11: unnamed unused input active-high </span>
<span style="color: #888888;"> line 12: unnamed unused input active-high </span>
<span style="color: #888888;"> line 13: unnamed unused input active-high </span>
<span style="color: #888888;"> line 14: unnamed unused input active-high </span>
<span style="color: #888888;"> line 15: unnamed unused input active-high </span>
<span style="color: #888888;"> line 16: unnamed unused input active-high </span>
<span style="color: #888888;"> line 17: unnamed "regulators:regulator@0" output active-high [used]</span>
<span style="color: #888888;"> line 18: unnamed unused input active-high </span>
<span style="color: #888888;"> line 19: unnamed unused input active-high </span>
<span style="color: #888888;"> line 20: unnamed unused input active-high </span>
<span style="color: #888888;"> line 21: unnamed unused input active-high </span>
<span style="color: #888888;"> line 22: unnamed unused input active-high </span>
<span style="color: #888888;"> line 23: unnamed unused input active-high </span>
<span style="color: #888888;"> line 24: unnamed unused input active-high </span>
<span style="color: #888888;"> line 25: unnamed unused input active-high </span>
<span style="color: #888888;"> line 26: unnamed unused input active-high </span>
<span style="color: #888888;"> line 27: unnamed unused input active-high </span>
<span style="color: #888888;"> line 28: unnamed unused input active-high </span>
<span style="color: #888888;"> line 29: unnamed unused input active-high </span>
<span style="color: #888888;"> line 30: unnamed unused input active-high </span>
<span style="color: #888888;"> line 31: unnamed unused input active-high</span>
<span style="color: #888888;">gpiochip1 - 32 lines:</span>
<span style="color: #888888;"> line 0: unnamed unused input active-high </span>
<span style="color: #888888;"> line 1: unnamed unused input active-high </span>
<span style="color: #888888;"> line 2: unnamed unused input active-high </span>
<span style="color: #888888;"> line 3: unnamed unused input active-high </span>
<span style="color: #888888;"> line 4: unnamed unused input active-high </span>
<span style="color: #888888;"> line 5: unnamed unused input active-high </span>
<span style="color: #888888;"> line 6: unnamed unused input active-high </span>
<span style="color: #888888;"> line 7: unnamed unused input active-high </span>
<span style="color: #888888;"> line 8: unnamed unused input active-high </span>
<span style="color: #888888;"> line 9: unnamed unused input active-high </span>
<span style="color: #888888;"> line 10: unnamed unused input active-high </span>
<span style="color: #888888;"> line 11: unnamed unused input active-high </span>
<span style="color: #888888;"> line 12: unnamed unused input active-high </span>
<span style="color: #888888;"> line 13: unnamed unused input active-high </span>
<span style="color: #888888;"> line 14: unnamed unused input active-high </span>
<span style="color: #888888;"> line 15: unnamed unused input active-high </span>
<span style="color: #888888;"> line 16: unnamed unused input active-high </span>
<span style="color: #888888;"> line 17: unnamed unused input active-high </span>
<span style="color: #888888;"> line 18: unnamed unused input active-high </span>
<span style="color: #888888;"> line 19: unnamed unused input active-high </span>
<span style="color: #888888;"> line 20: unnamed unused input active-high </span>
<span style="color: #888888;"> line 21: unnamed unused input active-high </span>
<span style="color: #888888;"> line 22: unnamed unused input active-high </span>
<span style="color: #888888;"> line 23: unnamed unused input active-high </span>
<span style="color: #888888;"> line 24: unnamed unused input active-high </span>
<span style="color: #888888;"> line 25: unnamed unused input active-high </span>
<span style="color: #888888;"> line 26: unnamed unused output active-high </span>
<span style="color: #888888;"> line 27: unnamed unused input active-high </span>
<span style="color: #888888;"> line 28: unnamed unused input active-high </span>
<span style="color: #888888;"> line 29: unnamed unused input active-high </span>
<span style="color: #888888;"> line 30: unnamed unused input active-high </span>
<span style="color: #888888;"> line 31: unnamed unused input active-high </span>
<span style="color: #888888;">gpiochip2 - 32 lines:</span>
<span style="color: #888888;"> line 0: unnamed unused input active-high </span>
<span style="color: #888888;"> line 1: unnamed "green" output active-high [used]</span>
<span style="color: #888888;"> line 2: unnamed unused input active-high </span>
<span style="color: #888888;"> line 3: unnamed unused input active-high </span>
<span style="color: #888888;"> line 4: unnamed unused input active-high </span>
<span style="color: #888888;"> line 5: unnamed unused input active-high </span>
<span style="color: #888888;"> line 6: unnamed unused input active-high </span>
<span style="color: #888888;"> line 7: unnamed unused input active-high </span>
<span style="color: #888888;"> line 8: unnamed unused input active-high </span>
<span style="color: #888888;"> line 9: unnamed unused input active-high </span>
<span style="color: #888888;"> line 10: unnamed unused input active-high </span>
<span style="color: #888888;"> line 11: unnamed unused input active-high </span>
<span style="color: #888888;"> line 12: unnamed unused input active-high </span>
<span style="color: #888888;"> line 13: unnamed unused input active-high </span>
<span style="color: #888888;"> line 14: unnamed unused input active-high </span>
<span style="color: #888888;"> line 15: unnamed unused input active-high </span>
<span style="color: #888888;"> line 16: unnamed unused input active-high </span>
<span style="color: #888888;"> line 17: unnamed unused input active-high </span>
<span style="color: #888888;"> line 18: unnamed unused input active-high </span>
<span style="color: #888888;"> line 19: unnamed unused input active-high </span>
<span style="color: #888888;"> line 20: unnamed unused input active-high </span>
<span style="color: #888888;"> line 21: unnamed unused input active-high </span>
<span style="color: #888888;"> line 22: unnamed unused input active-high </span>
<span style="color: #888888;"> line 23: unnamed unused input active-high </span>
<span style="color: #888888;"> line 24: unnamed unused input active-high </span>
<span style="color: #888888;"> line 25: unnamed unused input active-high </span>
<span style="color: #888888;"> line 26: unnamed unused input active-high </span>
<span style="color: #888888;"> line 27: unnamed unused input active-high </span>
<span style="color: #888888;"> line 28: unnamed unused input active-high </span>
<span style="color: #888888;"> line 29: unnamed unused input active-high </span>
<span style="color: #888888;"> line 30: unnamed unused input active-high </span>
<span style="color: #888888;"> line 31: unnamed unused input active-high</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Therefore, in order to figure out how its GPIOs connect to the SoC, we're going to have to do some digging into the board's schematics, then into the SoC's Reference Manual.</p><p style="text-align: left;">Thankfully, <a href="https://www.olimex.com/Products/OLinuXino/open-source-hardware" target="_blank">being open hardware</a>, the <a href="https://github.com/OLIMEX/OLINUXINO/tree/master/HARDWARE/iMX233-OLinuXino-Maxi" target="_blank">schematics are publicly available</a> (thank you Olimex!). The MAXI has a large, 40-pin, male connector on its side which is described in the schematic. Pretty much any GPIO line could be used, I decided to use the one labeled "PIN30".</p><p style="text-align: left;">Looking at the schematic:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJJSoMIuGub-e64h-YuH5isOP0xCPOAbm1tS3skPaoJji5VKmSTkWM4Ssr5L2_0c_Wt3JID-ALCJS-bvzYsD6pzDqgF2rd_xt76bZbG_f6Utpk6LsQLog5DPmPmFkPt3yecKLdwbRh3CjnilJUoX13KF_ormqZqd-x9-WaxAk2-V63UkgxM0ndRb9W/s718/imx233-gpio.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="535" data-original-width="718" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJJSoMIuGub-e64h-YuH5isOP0xCPOAbm1tS3skPaoJji5VKmSTkWM4Ssr5L2_0c_Wt3JID-ALCJS-bvzYsD6pzDqgF2rd_xt76bZbG_f6Utpk6LsQLog5DPmPmFkPt3yecKLdwbRh3CjnilJUoX13KF_ormqZqd-x9-WaxAk2-V63UkgxM0ndRb9W/s16000/imx233-gpio.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p style="text-align: left;">We can see that PIN30 is connected to pin #28 of the board connector. We can also see that PIN30 connects to the SoC's pin 81, and the the SoC knows this pin as <span style="font-family: courier;">GPMI_CE1N</span>.</p><p style="text-align: left;"><b>[NOTE: There seems to be a little mistake in this schematic since it shows the SoC's pin 81 not connected to anything. Thankfully that's not the case, and we can associate the SoC pin with the connector pin by the common wire name: PIN30]</b></p><p style="text-align: left;">Now if we look at the SoC's <a href="https://www.nxp.com/docs/en/reference-manual/IMX23RM.pdf" target="_blank">Reference Manual</a> and search for <span style="font-family: courier;">GPMI_CE1N</span> we find (on page 37-28):</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAhRkakL2y-jxsxPDvkIEhI-69Ti51NHqujlIYzMpkhi80AHoBPeNPxI2H-PdEJwl0L0yJHuV_t9jsiJlnGiYGRfmkwiaDO7REfTYGb8XoLFoeCYPYhTSY0D-z3YpFGHp83ebJ2YFHjMjzt2hcis2Rv30TtvmeEBS5H_rcqlFiEqqMp1wWL_3VPqQg/s604/imx233-bank2-pin27.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="75" data-original-width="604" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAhRkakL2y-jxsxPDvkIEhI-69Ti51NHqujlIYzMpkhi80AHoBPeNPxI2H-PdEJwl0L0yJHuV_t9jsiJlnGiYGRfmkwiaDO7REfTYGb8XoLFoeCYPYhTSY0D-z3YpFGHp83ebJ2YFHjMjzt2hcis2Rv30TtvmeEBS5H_rcqlFiEqqMp1wWL_3VPqQg/s16000/imx233-bank2-pin27.png" /></a></div><br /><p style="text-align: left;">and we also find (on page 37-7):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJHdGeu0hOrRIPiuz-tJkxjFQIiPqsPMLtTaHzTsvAL8PWGpjMuDIgfKA3XtMM14qYRS6Y3jDPIhpVjRD5XsMiIlH9Ryc4O5f2BW8ERSMdU30yiJwtP2CW6BWgg4phzkLum8N0Pv0VmM8LjXw-xt3MyR641sZjsBrzseMgQSqgt21DaZB_WWMksrYA/s663/imx233-ce1n.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="181" data-original-width="663" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJHdGeu0hOrRIPiuz-tJkxjFQIiPqsPMLtTaHzTsvAL8PWGpjMuDIgfKA3XtMM14qYRS6Y3jDPIhpVjRD5XsMiIlH9Ryc4O5f2BW8ERSMdU30yiJwtP2CW6BWgg4phzkLum8N0Pv0VmM8LjXw-xt3MyR641sZjsBrzseMgQSqgt21DaZB_WWMksrYA/s16000/imx233-ce1n.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p style="text-align: left;">Both of these confirm that the SoC pin known as <span style="font-family: courier;">GPMI_CE1N</span> is found in GPIO bank 2, pin 27.</p><p style="text-align: left;"><b>[NOTE: This SoC comes in 2 form factors: 128-pin QFP and 169-pin BGA. The schematics from Olimex show that they're using the <span style="font-family: courier;">MCIMX233CAG4C</span> specifically. Page 41-1 of the Reference Manual shows that the <span style="font-family: courier;">CAG4C</span> is the 128-pin LQFP (actually it shows that the <span style="font-family: courier;">CAG4B</span> is the 128-pin LQFP, but searching on the Internet shows that the <span style="font-family: courier;">CAG4C</span> is simply a later revision of the same device). When you're looking at the pin descriptions in the Reference Manual, make sure you're looking at the tables for the QFP specifically and not the BGA, otherwise you'll get the wrong GPIO bank/pin]</b></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhprjlPUhkU9cy3c063XQckXHxGgnmQY8Pvd04gL34_Zue3bffdE0dESAroWivLv0eB0YkbxZdvCQXYba5Zvhyskd4wgURJRooi0fDNQCn867GljmYsSpnQ0r0fUMoW4E_v3NHlH-t5ng-2S7bf_LbOOCXCb-rFxIKsBar_-FMJHjS1CLiHXOHF1K79/s655/imx233-cag4c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="159" data-original-width="655" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhprjlPUhkU9cy3c063XQckXHxGgnmQY8Pvd04gL34_Zue3bffdE0dESAroWivLv0eB0YkbxZdvCQXYba5Zvhyskd4wgURJRooi0fDNQCn867GljmYsSpnQ0r0fUMoW4E_v3NHlH-t5ng-2S7bf_LbOOCXCb-rFxIKsBar_-FMJHjS1CLiHXOHF1K79/s16000/imx233-cag4c.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p style="text-align: left;">Performing the following simple test on the target board with everything wired up correctly proves we've found the right place:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #c65d09; font-weight: bold;">root@imx233-olinuxino-maxi:~#</span> gpioset gpiochip2 <span style="color: #996633;">27</span><span style="color: #333333;">=</span><span style="color: #6600ee; font-weight: bold;">1</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">One thing that I did notice about this device compared to the other SBCs that I used for these boxes is that this SoC does run noticeably slower than the others. If I used <span style="font-family: courier;">systemd</span> for the init system the device would run just fine for a while, but then become completely unresponsive for quite a while (perhaps 30 seconds?). Then it would run perfectly fine for many minutes, but then be unresponsive. When it was possible to type in commands again, running <span style="font-family: courier;">cat /proc/loadavg</span> would show a lot of recent activity. Switching to <span style="font-family: courier;">sysvinit</span> gives a system that doesn't have unresponsive gaps.</p><p style="text-align: left;">I had decided that I was going to install an ssh server on all these devices so I could interact with them "in the field" should I so desire. As part of any device's first boot with an ssh server installed, a bunch of security keys need to be generated. Without exaggeration, installing an ssh server on this device causes the first boot to take well over 5 minutes before a command line is reached as the device generates/calculates its ssh keys. Maybe using <span style="font-family: courier;">dropbear</span> would be better? I didn't check. My guess is that <span style="font-family: courier;">dropbear</span> would need to generate its own initial keys as well, so it would probably run just as poorly on first boot?</p><p style="text-align: left;">I suspect the real source of the problem is the the random number generator code in the kernel. Random numbers produce the best security keys, but generating randomness from deterministic devices is difficult. Over the years the Linux kernel has had several iterations of the random-generating subsystem as people find issues. Most modern SoCs now come with circuitry specifically designed to generate randomness in order to feed the pool of entropy that is used to generate secure keys (for example). This new code assumes such units exist, but in older hardware they either don't exist, or the kernel's drivers haven't been updated to support the new functionality. In any case, generating the randomness required to create cryptographically secure keys (by some definition of "secure") takes a long time.</p><p style="text-align: left;">Conceptually box2 could be described by the following Fritzing diagram:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEucjJMTtq2fTObg6rfoFYPxnrPE3U-L4uxJH3GLij0T0XJ9GKVAkqZxq1diCcG0T883TZuWalJJ9reG_E_CFrHsoL8gFlo_bM4ppjdeHodQ-ECMCM6j0mE3I4m3Bsn4vuvo4g3hnrCviTW5-66iLHP-TixA8qLNrK9lTHb8mRMOjuu4jqp_3Xrb81/s3762/box2_bb.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2658" data-original-width="3762" height="452" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEucjJMTtq2fTObg6rfoFYPxnrPE3U-L4uxJH3GLij0T0XJ9GKVAkqZxq1diCcG0T883TZuWalJJ9reG_E_CFrHsoL8gFlo_bM4ppjdeHodQ-ECMCM6j0mE3I4m3Bsn4vuvo4g3hnrCviTW5-66iLHP-TixA8qLNrK9lTHb8mRMOjuu4jqp_3Xrb81/w640-h452/box2_bb.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div>Here's how the box looked partway through the build (I don't seem to have a pic of it when it was done):<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6gi02cKKKTvQL3d4iH-8HNTHxOFiaQz0ag0c1xzy8HYp5WpFrq2f4Gjx7zp2emHnBjoo9jGHLoAeuWcoDNH5Yq1aMd_GQLvfTbFAUWvTdkQ4lGbpbutrcRBvv60l3gKG12vciq6qdAxlQGEDmxdq0dJkZn7UA3hqSohixJtVDglT5ll0MwEVzx_SX/s512/box-imx233.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="288" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6gi02cKKKTvQL3d4iH-8HNTHxOFiaQz0ag0c1xzy8HYp5WpFrq2f4Gjx7zp2emHnBjoo9jGHLoAeuWcoDNH5Yq1aMd_GQLvfTbFAUWvTdkQ4lGbpbutrcRBvv60l3gKG12vciq6qdAxlQGEDmxdq0dJkZn7UA3hqSohixJtVDglT5ll0MwEVzx_SX/s16000/box-imx233.jpg" /></a></div><br /><p style="text-align: left;">Before installation:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6R1Ms0E355Nw4W0J5bf3hZ0Dm6nBE0dUQm7xGeN268YvNSA40YqTb1UztqwcrzhaNcLw_7eU3uK7G6XFftvGewotWDtA0JDc89wlrfcq4UaePIaczqceBF9WD0cHsliekqwc5TSKtpFcMGGwacuUMIyvC52ama2uf6xfUmVUu6L-uuKFWS5BZ_LwR/s384/box-imx233-install-before.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6R1Ms0E355Nw4W0J5bf3hZ0Dm6nBE0dUQm7xGeN268YvNSA40YqTb1UztqwcrzhaNcLw_7eU3uK7G6XFftvGewotWDtA0JDc89wlrfcq4UaePIaczqceBF9WD0cHsliekqwc5TSKtpFcMGGwacuUMIyvC52ama2uf6xfUmVUu6L-uuKFWS5BZ_LwR/s16000/box-imx233-install-before.jpg" /></a></div><br /><p style="text-align: left;"><br /></p><p style="text-align: left;">After installation:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikXzaHSiGyD1dL-vWgG0NaIngDyFKzDqfM-egqVRK3WhmJvp4jSNyCMgKWui_2H2UTncCMkvCS9zTzvvxoVpHY1wQnL0rHnFQAzp6QAvbVLIuAxFigmk4IKk-LDSiPJY9ScwvjOV2TSX4InTUT4ldmrE6fZ-q10Jv1Z1yj5VA0g1xa-vNFJmoeG0ow/s384/box-imx233-install-done.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikXzaHSiGyD1dL-vWgG0NaIngDyFKzDqfM-egqVRK3WhmJvp4jSNyCMgKWui_2H2UTncCMkvCS9zTzvvxoVpHY1wQnL0rHnFQAzp6QAvbVLIuAxFigmk4IKk-LDSiPJY9ScwvjOV2TSX4InTUT4ldmrE6fZ-q10Jv1Z1yj5VA0g1xa-vNFJmoeG0ow/s16000/box-imx233-install-done.jpg" /></a></div><p style="text-align: left;"><br /></p><p></p></div>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-6074858537532260712023-01-14T12:23:00.000-05:002023-01-15T00:28:30.003-05:00Coordinated Holiday Lights - box 1<p>The first box that I put together features a RaspberryPi 3 and accesses the network via ethernet-over-power (i.e. powerline ethernet). The RaspberryPi 3 runs on the Broadcom BCM2837; a 64-bit, quad-core, ARM Cortex-A53 SoC. My intention is to use this device to run the lights on the house and deck.</p><p>Parts:<br /></p><ul><li><a href="https://www.raspberrypi.com/products/raspberry-pi-3-model-b/" target="_blank">Raspberry Pi 3</a></li><li>Adafruit STEMMA Non-Latching Mini Relay (product: <a href="https://www.adafruit.com/product/4409" target="_blank">4409</a>)</li><li>Wago <a href="https://www.wago.com/ca-en/electrical-interconnections/installation-terminal-blocks-and-connectors/221" target="_blank">221 connectors</a> (221-412, 221-413, 221-415)</li><li>TP-Link <a href="https://www.tp-link.com/ca/home-networking/powerline/tl-pa7017-kit/" target="_blank">AV1000</a> powerline adapter</li><li>Mean Well <a href="https://www.meanwell-web.com/en-gb/ac-dc-single-output-enclosed-power-supply-output-rs--15--5" target="_blank">RS-15-5</a> switching power supply</li></ul><p>One of the nice things about the RasberryPi is that, like so many such similar boards, it can be powered via its header pins. Therefore a nice, compact switching power supply to convert between mains voltage and the 5V3A can be plugged directly into either of the 5V pins of the RPi's 40-pin header. I chose the Mean Well RS-15-5 switching power supply. Simply connect the 3 mains wires on one side, and take 5V and ground off from the remaining pins; plug these 2 into the RPi's header and you've got power. One significant little detail that I did stumble over with these power supplies is the "adjustment" screw. When I first plugged the power supply and the RPi together, the RPi couldn't boot. Hooking up a console cable I could see some of the messages coming through okay at the start, but then there would be a whole bunch of garbled characters on the console. Garbled and legible text would come and go as the device booted. It was quite odd. It was as if the baud rate was fluctuating as the board ran. The leds on the board would come on, blink a little bit, then obviously start over again. It was clear the board was in a reboot cycle. I was about to try a different device (fortunately I had bought a couple) when I noticed the "adjustment" screw. I never did end up measuring anything, but I noticed the screw was turned all the way to the left (counter-clockwise). On a hunch I turned the screw all the way to the right (clockwise) then suddenly everything worked just perfectly.</p><p>The standard RPi header has quite a few GPIOs, and any one of which could be used for controlling the relay. I chose (completely arbitrarily) to use GPIO21, pin 40. As part of prototyping, you can test out controlling pin 40 with the <span style="font-family: courier;">gpioset</span> program which is part of the <span style="font-family: courier;">libgpiod-tools</span> Yocto package. The <span style="font-family: courier;">gpioinfo</span> program can be used to dump out the Linux kernel's understanding of which GPIOs go where. I'm running this command on a Linux kernel 5.15.56:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #c65d09; font-weight: bold;">root@raspberrypi3-64:~#</span> gpioinfo
<span style="color: #888888;">gpiochip0 - 54 lines:</span>
<span style="color: #888888;"> line 0: "ID_SDA" unused input active-high </span>
<span style="color: #888888;"> line 1: "ID_SCL" unused input active-high </span>
<span style="color: #888888;"> line 2: "SDA1" unused input active-high </span>
<span style="color: #888888;"> line 3: "SCL1" unused input active-high </span>
<span style="color: #888888;"> line 4: "GPIO_GCLK" unused input active-high </span>
<span style="color: #888888;"> line 5: "GPIO5" unused input active-high </span>
<span style="color: #888888;"> line 6: "GPIO6" unused input active-high </span>
<span style="color: #888888;"> line 7: "SPI_CE1_N" unused input active-high </span>
<span style="color: #888888;"> line 8: "SPI_CE0_N" unused input active-high </span>
<span style="color: #888888;"> line 9: "SPI_MISO" unused input active-high </span>
<span style="color: #888888;"> line 10: "SPI_MOSI" unused input active-high </span>
<span style="color: #888888;"> line 11: "SPI_SCLK" unused input active-high </span>
<span style="color: #888888;"> line 12: "GPIO12" unused input active-high </span>
<span style="color: #888888;"> line 13: "GPIO13" unused input active-high </span>
<span style="color: #888888;"> line 14: "TXD1" unused input active-high </span>
<span style="color: #888888;"> line 15: "RXD1" unused input active-high </span>
<span style="color: #888888;"> line 16: "GPIO16" unused input active-high </span>
<span style="color: #888888;"> line 17: "GPIO17" unused input active-high </span>
<span style="color: #888888;"> line 18: "GPIO18" unused input active-high </span>
<span style="color: #888888;"> line 19: "GPIO19" unused input active-high </span>
<span style="color: #888888;"> line 20: "GPIO20" unused input active-high </span>
<span style="color: #888888;"> line 21: "GPIO21" unused input active-high</span>
<span style="color: #888888;"> line 22: "GPIO22" unused input active-high </span>
<span style="color: #888888;"> line 23: "GPIO23" unused input active-high </span>
<span style="color: #888888;"> line 24: "GPIO24" unused input active-high </span>
<span style="color: #888888;"> line 25: "GPIO25" unused input active-high </span>
<span style="color: #888888;"> line 26: "GPIO26" unused input active-high </span>
<span style="color: #888888;"> line 27: "GPIO27" unused input active-high </span>
<span style="color: #888888;"> line 28: "HDMI_HPD_N" unused input active-high </span>
<span style="color: #888888;"> line 29: "STATUS_LED_G" "led0" output active-high [used]</span>
<span style="color: #888888;"> line 30: "CTS0" unused input active-high </span>
<span style="color: #888888;"> line 31: "RTS0" unused input active-high </span>
<span style="color: #888888;"> line 32: "TXD0" unused input active-high </span>
<span style="color: #888888;"> line 33: "RXD0" unused input active-high </span>
<span style="color: #888888;"> line 34: "SD1_CLK" unused input active-high </span>
<span style="color: #888888;"> line 35: "SD1_CMD" unused input active-high </span>
<span style="color: #888888;"> line 36: "SD1_DATA0" unused input active-high </span>
<span style="color: #888888;"> line 37: "SD1_DATA1" unused input active-high </span>
<span style="color: #888888;"> line 38: "SD1_DATA2" unused input active-high </span>
<span style="color: #888888;"> line 39: "SD1_DATA3" unused input active-high </span>
<span style="color: #888888;"> line 40: "PWM0_OUT" unused input active-high </span>
<span style="color: #888888;"> line 41: "PWM1_OUT" unused input active-high </span>
<span style="color: #888888;"> line 42: "ETH_CLK" unused input active-high </span>
<span style="color: #888888;"> line 43: "WIFI_CLK" unused input active-high </span>
<span style="color: #888888;"> line 44: "SDA0" unused input active-high </span>
<span style="color: #888888;"> line 45: "SCL0" unused input active-high </span>
<span style="color: #888888;"> line 46: "SMPS_SCL" unused input active-high </span>
<span style="color: #888888;"> line 47: "SMPS_SDA" unused output active-high </span>
<span style="color: #888888;"> line 48: "SD_CLK_R" unused input active-high </span>
<span style="color: #888888;"> line 49: "SD_CMD_R" unused input active-high </span>
<span style="color: #888888;"> line 50: "SD_DATA0_R" unused input active-high </span>
<span style="color: #888888;"> line 51: "SD_DATA1_R" unused input active-high </span>
<span style="color: #888888;"> line 52: "SD_DATA2_R" unused input active-high </span>
<span style="color: #888888;"> line 53: "SD_DATA3_R" unused input active-high </span>
<span style="color: #888888;">gpiochip1 - 8 lines:</span>
<span style="color: #888888;"> line 0: "BT_ON" unused output active-high </span>
<span style="color: #888888;"> line 1: "WL_ON" unused output active-high </span>
<span style="color: #888888;"> line 2: "PWR_LED_R" "led1" output active-low [used]</span>
<span style="color: #888888;"> line 3: "LAN_RUN" unused output active-high </span>
<span style="color: #888888;"> line 4: "NC" unused input active-high </span>
<span style="color: #888888;"> line 5: "CAM_GPIO0" "cam1_regulator" output active-high [used]</span>
<span style="color: #888888;"> line 6: "CAM_GPIO1" unused output active-high </span>
<span style="color: #888888;"> line 7: "NC" unused input active-high</span>
</pre></td></tr></tbody></table></div>
<p>As you can see, some wonderful kernel developer has done a great job associating the various pins with their common names. One doesn't have to consult any datasheets or schematics to see that if I want to control GPIO21, all that is required is to fiddle with pin 21 of <span style="font-family: courier;">gpiochip0</span>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #c65d09; font-weight: bold;">root@raspberrypi3-64:~#</span> gpioset <span style="color: #6600ee; font-weight: bold;">0</span> <span style="color: #996633;">21</span><span style="color: #333333;">=</span><span style="color: #6600ee; font-weight: bold;">1</span>
</pre></td></tr></tbody></table></div>
<p>If everything is wired up correctly, then your relay should now be active. The <span style="font-family: courier;">gpioset</span> utility also understands chip names as well, so instead of saying "<span style="font-family: courier;">gpioset 0 21=1</span>" you could also write "<span style="font-family: courier;">gpioset gpiochip0 21=1</span>". To turn off the relay, run the same command setting "<span style="font-family: courier;">21=0</span>".</p><p>When working with relays, make sure to keep the mains and the electronics sides of the board separate. On the electronics side hook up the other 5V pin from the RPi header (i.e. the 5V pin not being used to supply power to the RPi from the switching power supply) to the relay's "Vin" pin, ground from the RPi to the relay's "GND" pin, and hook up the RPi's GPIO 21 (pin 40) to the relay's "Sig" pin. On the mains side make sure you come directly from mains power into the relay's "Common" connector. Relays have 2 modes: if you want your microcontroller to turn something on when it activates the relay, then connect the load to the "NO" (normally open) side. If you want your load to turn off when the microcontroller activates the relay, then connect your load to the "NC" (normally closed) side. In my case I want the lights to come on when the microcontroller activates the relay, therefore I connect my load to the NO side.</p><p><br /></p><p><b style="background-color: #fcff01; color: red;"><i><u>HUGE NOTE</u></i>: By convention: in the world of home electrical wiring in North America the black wire is the hot wire, the white is neutral, and the green is ground. However in the world of electronics the black wire is ground and the red wire is VIN (12V, 5V, 3V3, 1V8 etc). When looking at the following diagrams and pictures do not confuse the black, hot, home-wiring, AC wires with the black, ground, electronics, DC ground wires -- <i>they are separate!</i></b></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPpMXb1a5Vm8AnO-jDWeSEm43z4WBfpd-WHLXXmQmQQoDoPn-ugy-6ENqInUAedtYJFvPpDSoWnVDwK5P_oQWzgsrK-d0LEZByGniYDP7atW_bT38cAEYIHNmr7MvbRLQhxcIDg1UVA79-fw17UHiLRAgAb62h6iJGcHF-3gT81y2wusZ-jXFijTc4/s699/mains-relay.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="431" data-original-width="699" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPpMXb1a5Vm8AnO-jDWeSEm43z4WBfpd-WHLXXmQmQQoDoPn-ugy-6ENqInUAedtYJFvPpDSoWnVDwK5P_oQWzgsrK-d0LEZByGniYDP7atW_bT38cAEYIHNmr7MvbRLQhxcIDg1UVA79-fw17UHiLRAgAb62h6iJGcHF-3gT81y2wusZ-jXFijTc4/w640-h394/mains-relay.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p>The conceptual drawing of the complete box in Fritzing looks as follows:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiItQLC5be921R3hVeFpuSPwKmDPHF-NZaXqyY1SkxPWSsxEv1dfXfseaWPmWQbOFaovWJ7_zxYKU0druK5C5NAoq-JoZ9mEYVVYag56yo6t3AwZZ7AUANaU-I4Vsbg5FnUkQsp1k3UUV27CaxMJNYKHPV1qsQTTtjfQz2P58WGzsv2QunrK6FS4IuY/s3981/box1_bb.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3171" data-original-width="3981" height="510" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiItQLC5be921R3hVeFpuSPwKmDPHF-NZaXqyY1SkxPWSsxEv1dfXfseaWPmWQbOFaovWJ7_zxYKU0druK5C5NAoq-JoZ9mEYVVYag56yo6t3AwZZ7AUANaU-I4Vsbg5FnUkQsp1k3UUV27CaxMJNYKHPV1qsQTTtjfQz2P58WGzsv2QunrK6FS4IuY/w640-h510/box1_bb.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><p></p><div>The completed box looks like (oops! looks like I forgot to remove the serial console cable before taking this pic!):</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZuO2pwF4Lejr1v-HSHo3sVBV25FfWS1giBIWONjKBCvKF9G2mQR1TBwnshpsoXJkQpWRRnDiMKO2hA_a79qEwf1w71bx-368Je2IBNSOh60Z2yT0OV2Hk9zDgbVM9YBBv_Is_WvSyRd2eIo5qsS9g5iJZ0JtE9ONJnvMtkySwz504RIMbPuBIlDcU/s384/box-rpi3.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZuO2pwF4Lejr1v-HSHo3sVBV25FfWS1giBIWONjKBCvKF9G2mQR1TBwnshpsoXJkQpWRRnDiMKO2hA_a79qEwf1w71bx-368Je2IBNSOh60Z2yT0OV2Hk9zDgbVM9YBBv_Is_WvSyRd2eIo5qsS9g5iJZ0JtE9ONJnvMtkySwz504RIMbPuBIlDcU/s16000/box-rpi3.jpg" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div>Before installation:<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgizee_3aOJLf19HxytGlFqtan0QdVyLu7oQRmuz95kVqCG57wdH7NKydMBz08wojhKyBauS6Y4ZgEvdJ95QV_GIgG1wejt3ye2-tPBbuzVVOGB6zi7eLtoLrYPe3-3Ju8W6yCmte3aul_rzP96n28Qz-9_FPfXCuljpFGh2rjyqYs-NqrEIYoKZ6tV/s512/box-rpi3-install-before.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgizee_3aOJLf19HxytGlFqtan0QdVyLu7oQRmuz95kVqCG57wdH7NKydMBz08wojhKyBauS6Y4ZgEvdJ95QV_GIgG1wejt3ye2-tPBbuzVVOGB6zi7eLtoLrYPe3-3Ju8W6yCmte3aul_rzP96n28Qz-9_FPfXCuljpFGh2rjyqYs-NqrEIYoKZ6tV/s16000/box-rpi3-install-before.jpg" /></a></div><br /><div><div>After installation:</div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglG4MelJG8PWYwStq7wnqMBVH-tSPp5yn1oSUpMcdJ4c3Vybr6DTuK9B9tiF-giNGYvRy1J1ZRAOTUjCOi7d0D8cYs8rfftBGTJnb01YZa1vV3PVCGnaUmKINkDJbAoRAwUzq-kvjdYKcw_95m9kQUoRF7y8zZu6dCB7DHL-A14vF3cSlp6khpHuFF/s512/box-rpi3-install-done.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglG4MelJG8PWYwStq7wnqMBVH-tSPp5yn1oSUpMcdJ4c3Vybr6DTuK9B9tiF-giNGYvRy1J1ZRAOTUjCOi7d0D8cYs8rfftBGTJnb01YZa1vV3PVCGnaUmKINkDJbAoRAwUzq-kvjdYKcw_95m9kQUoRF7y8zZu6dCB7DHL-A14vF3cSlp6khpHuFF/s16000/box-rpi3-install-done.jpg" /></a></div><br /><div><br /></div>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-78045753861668033642023-01-12T11:54:00.000-05:002023-01-14T09:18:55.573-05:00Coordinated Holiday Lights - intro<p>I like putting lights up around the property for the holidays, and have run power to various locations over the years in support of this endeavour. I now have lights on the house (which includes the deck), on a bush in front of the house, on the gates (where the driveway meets the road), and on some fencing leading to the barn. In time I would like to put up even more lights in more locations. Currently each set of lights plugs into power individually, and (since I don't want these lights to be on all the time) each set of lights has its own way of turning off during the day and turning on at night. For variety, some locations use off-the-shelf light-sensor plugs, and other locations use off-the-shelf timer plugs.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3iZ7FP0mU7BpBBN1Byks8QPEKHw-6Z5rAvdgtQXP-_IlFyHBVFrH7mOp-tkZeWFqgrIpxSbgRvUM4ac3x69-K1CaRkang9VkPkYGp4w27ZO83iLbgYwtmr-CjT8M0JIw8JqyTGBiwyIJha_CPGz3DYPQr90dU1Z-WEkQwFzttrUcvZ81_kThfiA4M/s384/plugs.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="334" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3iZ7FP0mU7BpBBN1Byks8QPEKHw-6Z5rAvdgtQXP-_IlFyHBVFrH7mOp-tkZeWFqgrIpxSbgRvUM4ac3x69-K1CaRkang9VkPkYGp4w27ZO83iLbgYwtmr-CjT8M0JIw8JqyTGBiwyIJha_CPGz3DYPQr90dU1Z-WEkQwFzttrUcvZ81_kThfiA4M/s320/plugs.jpg" width="278" /></a></div><br /><p><br /></p><p>Now it's time to get fancy.</p><p>During the day all these lights are off; at night they're all on. But in between being all off or all on, each set of lights in each of these locations changes state at random times. In fact sometimes a set of lights controlled by a light-sensor changes state a couple times before settling down to one state or another. Wouldn't it be nice if they all turned on and off at the same time?<br /></p><p>One way to solve this problem would be to run extension cords to and from all these lights and then plug them all in at only one location. This would work on smaller properties, but unfortunately the distances between all the lights on my property doesn't make this practical for me. Another option would be to buy "smart" sockets... but where's the fun in that?</p><p>The light-sensor plugs have a couple drawbacks:<br /></p><ul style="text-align: left;"><li><span>if the light sensor and the lights it controls are in too close of proximity to each other, then they end up in a perpetual cycle, at night, of turning on then off then on then off...</span></li><li><span>if the light sensor is close to a driveway or road, then headlights from vehicles going past at night will trip the sensor and turn off the lights for a minute or two</span></li><li><span>the specific light-sensor plugs that I'm using have multiple settings that are selected by pushing a button on the device; the initial, power-on setting is to stay off; I like the "dawn to dusk" setting; unfortunately the device doesn't save your preference across power-cycles, therefore every time there is a power blip I need to go around to each device and set it back to "dawn to dusk" mode</span><br /></li></ul><p> The timer plugs also have a couple drawbacks:<br /></p><ul style="text-align: left;"><li><span>the amount of daylight changes every day, so each timer would need to be manually modified every couple weeks otherwise the lights they control will either be on for a portion of the day (when they should be off), and/or will be off for some part of the night (when they should be on)</span></li><li><span>in my experience, many of these timers keep time very poorly; as a result, a timer that is set to turn on or off every day at a specific time ends up drifting away from that time very noticeably and very quickly</span></li><li><span>any power outage will end up adjusting the "current time" of the device by the length of the power outage, resulting in more trips around the property to adjust the timers</span></li></ul><p><span>It's interesting that the winter solstice occurs in the middle of "holiday lights" season. So if you are using timers then you will want to be increasing the amount of "on"-time as you approach the solstice, then contract it as you leave the solstice behind.</span></p><p><span>Both of these solutions (light sensors and timers) have drawbacks. But even if one of them was a clear winner, lights in different locations would still turn on and off at different times; all the lights wouldn't be coordinated. The amount of light falling on different parts of the property varies quite a bit; so if I used light-sensor plugs everywhere, different areas would still turn on and off at different times. On the other hand, if I used timers everywhere it would be hard to precisely synchronize multiple timers. Even if they did start out perfectly synchronized, over time they would drift, and would need to be adjusted regularly for nothing else than to adjust to the amount of daylight. In other words, using timers everywhere would also not result in all the lights turning on and off simultaneously.</span></p><p><span>As a result I've decided to make something myself. I want to create a device that </span><span><span>can be used outdoors, and</span></span><span><span> provides an outlet whose on/off state is remotely controllable. This way I can send one command from a central controller and have all the lights turn on or off (as appropriate) simultaneously. Additionally, if I wanted to control specific outlets individually I would like to be able to do that as well.</span></span></p><p><span><span>Currently I will need 6 such devices (house + deck, bush, east gate, west gate, east fence, and west fence). </span></span>As an added twist, I've decided to use a different single board computer (SBC) for each unit I put together. There are literally hundreds of Linux-capable SBCs from which to choose, so why not give a bunch of them a try?</p><div><span></span></div>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com2tag:blogger.com,1999:blog-3897401118500109418.post-26529279993732576732021-02-23T14:37:00.009-05:002022-03-21T08:45:14.144-04:00GDB+OpenOCD an ADI Target with The Yocto Project/Openembedded<p><b><span style="color: red;">UPDATE</span>: </b>unfortunately the "fix" I suggest below doesn't work :-( It seemed to work yesterday because the half-dozen times or so that I used it, the connection, coincidentally, was robust. But running it many many dozens of times today, I do see it failing. As does the cross-gdb binary supplied by ADI. So there's something wrong with the connection between openocd and gdb. Sometimes they connect just fine, other times something goes wrong. Probably an issue with the closed-source openocd binary, or an issue with the openocd configuration files for the JTAG or the target.</p>
<hr />
<p><br /></p><p>I'm working with a board from Analog Devices. Unfortunately it's not possible to use upstream openocd. You have to use the openocd binary that comes with their Developer's Kit.</p><p>Although I'm forced to use their openocd binary, I wanted to be able to use my own cross-gdb; one that I could build as part of my Yocto/OE-generated SDK. But whenever I tried connecting my cross-gdb (arm-oe-linux-gnueabi-gdb) to their openocd I would get errors, and further debugging wasn't possible.</p><p>I start their openocd and get the regular openocd information:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">#</span> bin/openocd --search share/openocd/scripts/ -f interface/ice1000.cfg -f target/adspsc58x.cfg
<span style="color: #777777;">Open On-Chip Debugger (Analog Devices CCES 2.8.0 OpenOCD 0.9.0-g5030ad7) 0.9.0</span>
<span style="color: #777777;">Licensed under GNU GPL v2</span>
<span style="color: #777777;">Report bugs to <processor.tools.support@analog.com></span>
<span style="color: #777777;">adapter speed: 1000 kHz</span>
<span style="color: #777777;">Info : transports supported by the debug adapter: "jtag", "swd"</span>
<span style="color: #777777;">Info : auto-select transport "jtag"</span>
<span style="color: #777777;">halt and restart using CTI</span>
<span style="color: #777777;">trst_only separate trst_push_pull</span>
<span style="color: #777777;">Info : ICE-1000 firmware version is 1.0.2</span>
<span style="color: #777777;">Info : clock speed 1000 kHz</span>
<span style="color: #777777;">Info : JTAG tap: adspsc58x.adjc tap/device found: 0x128080cb (mfg: 0x065, part: 0x2808, ver: 0x1)</span>
<span style="color: #777777;">Info : JTAG tap: adspsc58x.dap enabled</span>
<span style="color: #777777;">Info : adspsc58x.dap: hardware has 3 breakpoints, 2 watchpoints</span>
<span style="color: #777777;">Info : adspsc58x.dap: but you can only set 1 watchpoint</span>
</pre></div>
<p>I then startup the arm-oe-linux-gnueabi-gdb that was built as part of the Yocto/OE SDK that I generated:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> arm-oe-linux-gnueabi-gdb u-boot-sc589-ezkit
<span style="color: #777777;">GNU gdb (GDB) 8.2</span>
<span style="color: #777777;">Copyright (C) 2018 Free Software Foundation, Inc.</span>
<span style="color: #777777;">License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html></span>
<span style="color: #777777;">This is free software: you are free to change and redistribute it.</span>
<span style="color: #777777;">There is NO WARRANTY, to the extent permitted by law.</span>
<span style="color: #777777;">Type "show copying" and "show warranty" for details.</span>
<span style="color: #777777;">This GDB was configured as "--host=x86_64-oesdk-linux --target=arm-oe-linux-gnueabi".</span>
<span style="color: #777777;">Type "show configuration" for configuration details.</span>
<span style="color: #777777;">For bug reporting instructions, please see:</span>
<span style="color: #777777;"><http://www.gnu.org/software/gdb/bugs/>.</span>
<span style="color: #777777;">Find the GDB manual and other documentation resources online at:</span>
<span style="color: #777777;"> <http://www.gnu.org/software/gdb/documentation/>.</span>
<span style="color: #777777;">For help, type "help".</span>
<span style="color: #777777;">Type "apropos word" to search for commands related to "word"...</span>
<span style="color: #777777;">Reading symbols from u-boot-sc589-ezkit...done.</span>
<span style="color: #348c00;">(gdb)</span>
</pre></div>
<p>So far, so good. However, the moment I connect the two… In gdb I get:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">(gdb)</span> <span style="color: #777777;">target remote :3333</span>
<span style="color: #777777;">Remote debugging using :3333</span>
<span style="color: #777777;">warning: remote target does not support file transfer, attempting to access files from local filesystem.</span>
<span style="color: #777777;">warning: Unable to find dynamic linker breakpoint function.</span>
<span style="color: #777777;">GDB will be unable to debug shared library initializers</span>
<span style="color: #777777;">and track explicitly loaded dynamic code.</span>
</pre></div>
<p>and in openocd I get:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">Info : accepting 'gdb' connection on tcp/3333</span>
<span style="color: #777777;">Warn : system reset not supported for ADSP-SC58x silicon revision 0.0 and 0.1</span>
<span style="color: #777777;">Info : ttbcr 0ttbr0 0ttbr1 0</span>
<span style="color: #777777;">Info : adspsc58x.dap rev 1, partnum c05, arch f, variant 0, implementor 41</span>
<span style="color: #777777;">Info : number of cache level 1</span>
<span style="color: #777777;">Info : adspsc58x.dap cluster 0 core 0 mono core</span>
<span style="color: #777777;">target state: halted</span>
<span style="color: #777777;">target halted in Thumb state due to debug-request, current mode: Supervisor</span>
<span style="color: #777777;">cpsr: 0x800001f3 pc: 0x00004810</span>
<span style="color: #777777;">MMU: disabled, D-Cache: disabled, I-Cache: disabled</span>
<span style="color: #777777;">semihosting is enabled</span>
<span style="color: #777777;">Error: Timeout waiting for cortex_a_exec_opcode</span>
<span style="color: #777777;">Error: Timeout waiting for InstrCompl=1</span>
<span style="color: #777777;">Warn : negative acknowledgment, but no packet pending</span>
<span style="color: #777777;">Error: Timeout waiting for InstrCompl=1</span>
<span style="color: #777777;">Error: Timeout waiting for InstrCompl=1</span>
<span style="color: #777777;">Warn : negative acknowledgment, but no packet pending</span>
<span style="color: #777777;">Error: Timeout waiting for InstrCompl=1</span>
<span style="color: #777777;">Error: Timeout waiting for InstrCompl=1</span>
<span style="color: #777777;">Warn : negative acknowledgment, but no packet pending</span>
<span style="color: #777777;">Error: Timeout waiting for InstrCompl=1</span>
<span style="color: #777777;">Error: Timeout waiting for InstrCompl=1</span>
<span style="color: #777777;">Warn : negative acknowledgment, but no packet pending</span>
<span style="color: #777777;">Error: Timeout waiting for InstrCompl=1</span>
</pre></div>
<p>Searching the Internet for solutions I was excited to find that the gdb "set sysroot <path>" was supposed to solve my problems, but it didn't. However the "set solib-absolute-prefix <path>" did! Simply set this option to the absolute path of the Yocto/OE-generated rootfs and everything works again.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> arm-oe-linux-gnueabi-gdb u-boot-sc589-ezkit
<span style="color: #777777;">GNU gdb (GDB) 8.2</span>
<span style="color: #777777;">Copyright (C) 2018 Free Software Foundation, Inc.</span>
<span style="color: #777777;">License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html></span>
<span style="color: #777777;">This is free software: you are free to change and redistribute it.</span>
<span style="color: #777777;">There is NO WARRANTY, to the extent permitted by law.</span>
<span style="color: #777777;">Type "show copying" and "show warranty" for details.</span>
<span style="color: #777777;">This GDB was configured as "--host=x86_64-oesdk-linux --target=arm-oe-linux-gnueabi".</span>
<span style="color: #777777;">Type "show configuration" for configuration details.</span>
<span style="color: #777777;">For bug reporting instructions, please see:</span>
<span style="color: #777777;"><http://www.gnu.org/software/gdb/bugs/>.</span>
<span style="color: #777777;">Find the GDB manual and other documentation resources online at:</span>
<span style="color: #777777;"> <http://www.gnu.org/software/gdb/documentation/>.</span>
<span style="color: #777777;">For help, type "help".</span>
<span style="color: #777777;">Type "apropos word" to search for commands related to "word"...</span>
<span style="color: #777777;">Reading symbols from u-boot-sc589-ezkit...done.</span>
<span style="color: #348c00;">(gdb)</span> <span style="color: #777777;">set solib-absolute-prefix /z/2.6-build-thud/sc589-ezkit/build/tmp-glibc/work/adsp_sc589_ezkit-oe-linux-gnueabi/core-image-minimal/1.0-r0/rootfs/</span>
<span style="color: #348c00;">(gdb)</span> <span style="color: #777777;">target remote :3333</span>
<span style="color: #777777;">Remote debugging using :3333</span>
<span style="color: #777777;">warning: Unable to find dynamic linker breakpoint function.</span>
<span style="color: #777777;">GDB will be unable to debug shared library initializers</span>
<span style="color: #777777;">and track explicitly loaded dynamic code.</span>
<span style="color: #777777;">0x00005392 in ?? ()</span>
<span style="color: #348c00;">(gdb)</span> <span style="color: #777777;">load init-sc589-ezkit.elf </span>
<span style="color: #777777;">Loading section .text, size 0x510 lma 0x20080000</span>
<span style="color: #777777;">Start address 0x20080024, load size 1296</span>
<span style="color: #777777;">Transfer rate: 24 KB/sec, 1296 bytes/write.</span>
<span style="color: #348c00;">(gdb)</span> <span style="color: #777777;">c</span>
<span style="color: #777777;">Continuing.</span>
<span style="color: #777777;">^C</span>
<span style="color: #777777;">Program received signal SIGINT, Interrupt.</span>
<span style="color: #777777;">0x00005394 in ?? ()</span>
<span style="color: #348c00;">(gdb)</span> <span style="color: #777777;">load u-boot-sc589-ezkit</span>
<span style="color: #777777;">Loading section .text, size 0x2d59c lma 0xc2200000</span>
<span style="color: #777777;">Loading section .rodata, size 0xb3a7 lma 0xc222d59c</span>
<span style="color: #777777;">Loading section .hash, size 0x18 lma 0xc2238944</span>
<span style="color: #777777;">Loading section .data, size 0x2458 lma 0xc223895c</span>
<span style="color: #777777;">Loading section .got.plt, size 0xc lma 0xc223adb4</span>
<span style="color: #777777;">Loading section .u_boot_list, size 0x894 lma 0xc223adc0</span>
<span style="color: #777777;">Loading section .rel.dyn, size 0x7308 lma 0xc223b654</span>
<span style="color: #777777;">Loading section .dynsym, size 0x30 lma 0xc224295c</span>
<span style="color: #777777;">Loading section .dynstr, size 0x1 lma 0xc224298c</span>
<span style="color: #777777;">Loading section .dynamic, size 0x90 lma 0xc2242990</span>
<span style="color: #777777;">Loading section .interp, size 0x14 lma 0xc2242a20</span>
<span style="color: #777777;">Loading section .gnu.hash, size 0x18 lma 0xc2242a34</span>
<span style="color: #777777;">Start address 0xc2200000, load size 272968</span>
<span style="color: #777777;">Transfer rate: 32 KB/sec, 10498 bytes/write.</span>
<span style="color: #348c00;">(gdb)</span> <span style="color: #777777;">c</span>
<span style="color: #777777;">Continuing.</span>
</pre></div>
<p><i style="font-weight: bold;">NOTE:</i> both the init-sc589-ezkit.elf and the u-boot-sc589-ezkit binaries are the ones I have built via Yocto/OE. So it's possible to build and use your own cross-gdb, initializer (init-sc589-ezkit-elf), and u-boot that are built with Yocto/OE.</p><p>Notice, as well, that I still get those warnings about not being able to find dynamic linker breakpoints, but at least I'm able to proceed.</p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-86858111424418301892021-01-29T22:37:00.001-05:002022-03-21T08:45:08.472-04:00Sensing Temperature with a RaspberryPi - pt2<p>In my <a href="https://twoerner.blogspot.com/2021/01/sensing-temperature-with-raspberrypi.html" target="_blank">previous post</a> I started a conversation around the details of sensing a temperature with a RaspberryPi. That post discussed using the cheapest temperature sensor available: a thermistor. Using a thermistor with an RPi is cheap, but not very straight-forward: an ADC is required, we need to communicate with that ADC (over SPI in my particular case), a voltage divider circuit is required to convert a varying resistance into a varying voltage, and we need some funky math in order to account for the sensor's non-linearity with respect to resistance versus temperature over a range of temperatures. Not to mention the further adjustments we need to make in order to account for the self-heating of the thermistor device itself.</p><p>However, learning how to work with one resistive sensor opens the door to working with a whole host of other resistive sensors (light sensors, pressure sensors, potentiometers, sliders, joysticks, etc). So while reading temperature in this way is challenging, the tricks learned along the way are useful in other common electronic designs as well.</p><p>My examples use a RaspberryPi specifically because I wanted to show an end-to-end example of reading an actual temperature with an actual SBC. From evaluating various temperature devices, choosing and buying one… all the way to connecting it to the RaspberryPi and reading the temperature in user-space. However, any of a large number of SBCs could be used. Although these posts are RaspberryPi-specific, many of the steps and concepts can be applied to a wide range of Linux-capable SBCs.</p><p>Continuing along with the discussion of reading a temperature with a RaspberryPi, this post will discuss a different class of temperature sensor.</p><h3 style="text-align: left;">Digital Thermometer</h3><p style="text-align: left;">At the polar opposite end of the spectrum from the hard-to-work-with thermistor are a class of temperature-sensing devices I'm calling "digital thermometers". I've seen that phrase used in a couple places, but the term isn't universal.</p><p style="text-align: left;">Whereas simple devices, such as the thermistor, require you to add various other components to your design and perform a complicated conversion from resistance to temperature, a digital thermometer is usually wired directly to the RPi and all that you need to do is read a temperature value directly from the device itself. There are no hoops to jump through to account for self-heating, or 3rd-order transfer functions to implement to adjust for the non-linear relationship between changing resistance versus changing temperature, no extra components to add to your design, and no circuitry you need to figure out and measure to improve the accuracy of your calculation.</p><p style="text-align: left;">The digital thermometer handles <i>all</i> of these things itself and simply provides a temperature (or something that is easily translated into a temperature). Conceptually it's as if all the pieces that were discussed in the previous post (except for the inter-chip communication) were encapsulated together into the sensor (including some of the software that would have needed to be written for the RPi):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-QgyeWNeF7hI/YAYH8C6RB_I/AAAAAAAAlLM/gZNbHdrpoPQpNcVvAKTZO-0F1dYo9t84gCLcBGAsYHQ/s1340/digital-thermometer-device.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="631" data-original-width="1340" height="302" src="https://1.bp.blogspot.com/-QgyeWNeF7hI/YAYH8C6RB_I/AAAAAAAAlLM/gZNbHdrpoPQpNcVvAKTZO-0F1dYo9t84gCLcBGAsYHQ/w640-h302/digital-thermometer-device.png" width="640" /></a></div><br /><p style="text-align: left;">NOTE: I'm not trying to imply that digital thermometers are based on thermistors; in fact according to their datasheets they are not. But I'm trying to relate back to case of the thermistor to show how much more advanced these devices are.</p><p style="text-align: left;">Examples of digital thermometers include:</p><p style="text-align: left;"></p><ul style="text-align: left;"><li>TMP102 from Sparkfun</li><li>Si7021 from Adafruit</li><li>TC72</li><li>DS18B20</li></ul><p style="text-align: left;">There are dozens (or hundreds?) of digital thermometers from which to choose. Select the accuracy, the range of temperatures you want to measure, your favourite inter-IC communication bus, and you're mostly done. Many of these devices have come about thanks to the <i>maker</i> movement. Taking sophisticated ICs, putting them on breadboard-friendly break-out boards, and adding any required circuitry makes successful projects easier. In addition to the hardware, most of these devices also come with (mostly Python) libraries, just in case neither hardware nor software are your strong suits when working with electronics ;-)</p><h4 style="text-align: left;">TMP102</h4><p style="text-align: left;">The <a href="https://www.sparkfun.com/products/13314" target="_blank">TMP102 temperature break-out board from Sparkfun</a> has the following characteristics:</p><p style="text-align: left;"></p><ul style="text-align: left;"><li>a resolution of: 12 bits</li><li>a range of: -25°C to +85°C</li><li>an accuracy of: ±0.5°C</li><li>and communicates over: I2C</li></ul><p style="text-align: left;">If you decide to forgo the Python library you'll need to know the format of the data you'll receive from the device. Simply refer to the datasheet and you'll find:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-Bm6aTBIgdWg/YAYWCIgr4QI/AAAAAAAAlLY/lCUybolsEMIGCxRDMlbjNBysLyTILPLngCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="77" data-original-width="472" src="https://lh3.googleusercontent.com/-Bm6aTBIgdWg/YAYWCIgr4QI/AAAAAAAAlLY/lCUybolsEMIGCxRDMlbjNBysLyTILPLngCLcBGAsYHQ/s16000/image.png" /></a></div><br />The upper-case <i>D</i>s represent the value to the left of the decimal point, the lower-case <i>d</i>s represent the fractions. If a whole-number calculation of the device's temperature will suffice, simply take the first byte that is given and ignore the second.<p></p><h4 style="text-align: left;">Si7021</h4><p style="text-align: left;">The <a href="https://www.adafruit.com/product/3251" target="_blank">Si7021 is an example of a digital thermometer from Adafruit</a>. It's <a href="https://cdn-learn.adafruit.com/assets/assets/000/035/931/original/Support_Documents_TechnicalDocs_Si7021-A20.pdf" target="_blank">specs</a> are:</p><p style="text-align: left;"></p><ul style="text-align: left;"><li>configurable from 11-bit to 14-bit resolution</li><li>-10°C to +85°C</li><li>±0.4°C</li><li>I2C</li></ul><p style="text-align: left;">The Si7021 provides an example of a digital thermometer that doesn't, exactly, give you a temperature, but it gives you something (a "Temp_Code") that is easy to convert to a temperature:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-MRjalLOcFdo/YAYYSapXulI/AAAAAAAAlLk/1-qKDiXY-4M6g-T09S-Mdhc_bcRgEx7HwCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="61" data-original-width="359" src="https://lh3.googleusercontent.com/-MRjalLOcFdo/YAYYSapXulI/AAAAAAAAlLk/1-qKDiXY-4M6g-T09S-Mdhc_bcRgEx7HwCLcBGAsYHQ/s16000/image.png" /></a></div><br /><p></p><h4 style="text-align: left;">TC72</h4><p style="text-align: left;">I can't find any examples of the TC72 on a maker-friendly break-out board but there are generic break-out boards to which it could be attached.</p><p style="text-align: left;"></p><ul style="text-align: left;"><li>10-bit</li><li>-40°C to +85°C</li><li>±2°C</li><li>SPI</li></ul><p style="text-align: left;">Data format:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-4_2TRfs4mxs/YAYY5f3ptMI/AAAAAAAAlLs/Bxu-zsah-xImg12Nw7HshJSJ55W1fnP3ACLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="77" data-original-width="429" src="https://lh3.googleusercontent.com/-4_2TRfs4mxs/YAYY5f3ptMI/AAAAAAAAlLs/Bxu-zsah-xImg12Nw7HshJSJ55W1fnP3ACLcBGAsYHQ/s16000/image.png" /></a></div><br /><p></p><h4 style="text-align: left;">DS18B20</h4><p style="text-align: left;">The DS18B20 is a very popular temperature-sensing device, and with good reason. In addition to its great specs, it is available both as a <a href="https://www.digikey.ca/en/products/detail/maxim-integrated/DS18B20Z/956982" target="_blank">discrete</a> <a href="https://www.digikey.ca/en/products/detail/maxim-integrated/DS18B20/956983" target="_blank">component</a>, as well as in a <a href="https://www.adafruit.com/product/3846" target="_blank">water-proof temperature-appropriate housing</a>.</p>
<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="640" data-original-width="640" height="200" src="https://1.bp.blogspot.com/-5WSw5Qm9qC0/YAYbJe945iI/AAAAAAAAlMA/t6Z5JO3V_PQ2_8mbXNUYa-Zmrz-Xw64BwCLcBGAsYHQ/w200-h200/175_21-0041_SA_8.webp" width="200" />
<img border="0" data-original-height="640" data-original-width="640" height="200" src="https://1.bp.blogspot.com/-2oJmsLS6IR8/YAYbUtnG3QI/AAAAAAAAlME/jYANG2yErwg8Aq44_gKlSdw-4Wp19ffggCLcBGAsYHQ/w200-h200/406-TO-92.webp" width="200" />
<img border="0" data-original-height="728" data-original-width="970" height="240" src="https://1.bp.blogspot.com/-c844oOyGqgQ/YAYb3j0CIuI/AAAAAAAAlMQ/G_vOYF8GricahtMrXMNlQtOJrf6QZaSaQCLcBGAsYHQ/w320-h240/3846-02.jpg" width="320" />
</div>
<p style="text-align: left;"><br /></p><p style="text-align: left;"></p>
<ul style="text-align: left;"><li>configurable 9-bit to 12-bit resolution</li><li>-55°C to +125°C</li><li>±0.5°C accuracy</li><li>1-wire communication protocol</li></ul><p style="text-align: left;">It's data format is as follows, and is very similar to a 16-bit signed 2's complement representation:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-cc71B0DUUC4/YAYaKKYC-BI/AAAAAAAAlL4/EjZ-Hylf8P8Hlm2GyeDofPthkYnQwc4MgCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="77" data-original-width="464" src="https://lh3.googleusercontent.com/-cc71B0DUUC4/YAYaKKYC-BI/AAAAAAAAlL4/EjZ-Hylf8P8Hlm2GyeDofPthkYnQwc4MgCLcBGAsYHQ/s16000/image.png" /></a></div><br /><p></p><p></p><h3 style="text-align: left;">Designing for Multiple Sensors</h3><p style="text-align: left;">In many situations the goal is to put one temperature sensor in an area (e.g. to measure the temperature of a room). For these situations, hooking up one temperature sensor to one SBC and distributing one set of these in each area will suffice. However, in other situations, the goal is to distribute a lot of sensors in a small area (e.g. monitoring the supply and return temperatures of a multi-zone HVAC system). Hooking up 1 or 2 sensors via I2C or SPI to one RaspberryPi isn't too hard, but trying to connect a dozen or more devices on these same buses can be a challenge. Another option would be to use a dozen RaspberryPis with 1 or 2 sensors each, but that's getting silly.</p><p style="text-align: left;">The problem lies with how these buses were designed, and the assumptions that were used when designing them.</p><h4 style="text-align: left;">SPI</h4><p style="text-align: left;">The SPI bus consists of 1 clock line and 2 data lines (one for each direction):</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-aUKUVVPbXKQ/YBRIydF2WMI/AAAAAAAAlZI/ckKRh6DIGpYAcl0cwdT1VWTfArRk4qjiACLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="109" data-original-width="350" src="https://lh3.googleusercontent.com/-aUKUVVPbXKQ/YBRIydF2WMI/AAAAAAAAlZI/ckKRh6DIGpYAcl0cwdT1VWTfArRk4qjiACLcBGAsYHQ/s16000/image.png" /></a></div>The specific slave device to which the master wants to talk is selected using a physical chip select line. When a design calls for multiple SPI devices, multiple chip select lines need to be used:<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-I4OHDuHkOZQ/YBRKRVBlVoI/AAAAAAAAlZU/XM6DzSFuS6U5IAYWFElGirVnYK8GuEWegCLcBGAsYHQ/s350/SPI_three_slaves.svg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="278" data-original-width="350" src="https://1.bp.blogspot.com/-I4OHDuHkOZQ/YBRKRVBlVoI/AAAAAAAAlZU/XM6DzSFuS6U5IAYWFElGirVnYK8GuEWegCLcBGAsYHQ/s16000/SPI_three_slaves.svg.png" /></a></div><p style="text-align: left;">The above diagram shows a master with one SPI bus that has 3 chip selects on it. The standard RaspberryPi 40-pin expansion header <a href="https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md" target="_blank">has two SPI buses</a>. The first SPI bus (SPI0) exposes 2 chip selects, and the second SPI bus (SPI1) exposes 3 chip selects.</p><p style="text-align: left;">Pins 19 and 21 are the 2 data lines for SPI0, pin 23 is the SPI0 clock pin, and pins 24 and 26 are the 2 chip selects for SPI0.</p><p style="text-align: left;">Pins 38 and 35 are the 2 data lines for SPI1, pin 40 is the SPI1 clock pin, and pins 12, 11, and 36 are the chip selects for SPI1.</p><p style="text-align: left;">All of the pins for SPI0 are readily available on the 40-pin header. The data lines and clock pins are available for SPI1 as well. However, the 3 chip selects for SPI1 are not the primary functions of those pins, so extra setup is required to set those chip select pins for SPI mode.</p><p style="text-align: left;">If you wanted to hook up more than 2 devices to the RaspberryPi's SPI0 bus you would need more chip select lines; the same is true for the Pi's SPI1 bus as well. Setting up more chip select lines requires some hardware work and tweaks to the driver software. It's possible, but it's getting complicated due to the nature of how the SPI bus works.</p><p style="text-align: left;">Another way to connect multiple devices to an SPI bus is as follows:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-CrHwTZk0IQ0/YBROrI5ShaI/AAAAAAAAlZo/mdK78iufPEs9_cDDkqa3ZYh-empZhi-JACLcBGAsYHQ/s350/SPI_three_slaves_daisy_chained.svg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="278" data-original-width="350" src="https://1.bp.blogspot.com/-CrHwTZk0IQ0/YBROrI5ShaI/AAAAAAAAlZo/mdK78iufPEs9_cDDkqa3ZYh-empZhi-JACLcBGAsYHQ/s16000/SPI_three_slaves_daisy_chained.svg.png" /></a></div><p style="text-align: left;">This is an example of connecting multiple SPI devices in a daisy-chain topography. One chip select always selects all devices at the same time, but the data from the first device travels to the next device down the chain, and so on, until the last device connects back to the master. This is the topology used for JTAG. In theory a large number of devices can be connected to one SBC using this topology. However, with this design it's not possible for the master to query any one device at a time, it must always clock enough times to get all the data from all the devices with each request. The slaves themselves must also support a pass-through mode which enables them to save up the received bits and send them along after they've put their own data on the data line.</p><p style="text-align: left;">In other words, this topology is also complicated and not always possible.</p><p style="text-align: left;">Whether you are using the first topology (multiple chip select lines) or have daisy-chained your devices together, there is no way for your software to know how you've wired everything together. Give 10 people the same two SPI devices to connect to the RaspberryPi's SPI0 bus and half of them will connect device A to chip-select 0 and the other half of them will connect device B to chip-select 0. Neither arrangement is wrong, but these differences need to be taken into account. As a result, SPI buses are not <i>discoverable</i>. There is no way for Linux to know, <i>a-priori</i>, the devices to which it is connected or how they've been wired up. There's no unique ID that can be sent to let Linux know exactly what's connected to where. Therefore, there's no way Linux can do all the work for you; you need to write some code for your specific arrangement, and therefore are responsible for interpreting the data you receive from each device. Plus this code needs to be flexible enough to allow the user to specify the wiring so your code knows where to look for its data.</p><h4 style="text-align: left;">I2C</h4><p style="text-align: left;">With I2C there is 1 data line and 1 clock line:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Z1LhfeE_VDg/YBRQdVbHZKI/AAAAAAAAlZ0/9m1IcFBuJMs5L_xWK7ecXk_V_AGz6_jAQCLcBGAsYHQ/s220/i2c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="78" data-original-width="220" src="https://1.bp.blogspot.com/-Z1LhfeE_VDg/YBRQdVbHZKI/AAAAAAAAlZ0/9m1IcFBuJMs5L_xWK7ecXk_V_AGz6_jAQCLcBGAsYHQ/s16000/i2c.png" /></a></div><p style="text-align: left;">Notice that there are no chip select lines. The master specifies the slave with which it wishes to communicate by providing an address as part of the message preamble. This has the added side-effect of reducing the data throughput rate since some part of every communication is taken up specifying an address. The original I2C spec specifies 7 bits to be used for these addresses; meaning there are only 128 unique address possibilities. With 1000s and 1000s of I2C devices on the market, you can be assured the possibility for address collisions is more than probable! This <i>address</i> isn't based on topology or related in any way to a device's position on the bus. This address is a number that is burned into the device, and when the device sees this number in the preamble of a message, it responds. Each I2C device has to know the address to which it is to respond. For many I2C devices an address is chosen by the manufacturer and simply burned into its circuitry. This address is specified in the device's datasheet. There is no central repository or authority dispensing these addresses, so manufacturers are free to use whatever address they want. Fancier I2C devices use from one to three external pins to allow the user to modify some part of the I2C address; the rest of the address is burned into the device. When the device is placed into its circuit these pins are either grounded or tied high to change the address; at which point their address becomes static. In recent years there have been new revisions of the I2C spec that allow for 10-bit addresses, but the adoption rate has been slow.</p><p style="text-align: left;">Therefore, trying to attach multiple of the exact same device to a RaspberryPi becomes tricky. If you're lucky you might be able to change 3 of the 7 address pins, giving you the ability to add up to 8 of the same device to each I2C bus your SBC exposes… but only if you're lucky and your specific device provides these address pins. Otherwise each I2C bus on your SBC can only accommodate up to 1 instance of a specific device if that device uses a fixed address.</p><p style="text-align: left;">The standard 40-pin expansion header on the RaspberryPi <a href="https://www.raspberrypi.org/documentation/usage/gpio/" target="_blank">includes 1 I2C bus</a>: I2C1. Pin 3 is the I2C1 data line, and pin 5 is the I2C1 clock pin.</p><p style="text-align: left;">This situation (regarding I2C device addressing) means that the I2C bus is not <i>discoverable</i>. You can't connect a random bunch of I2C devices to your SBC and have Linux magically know which devices you have connected, and therefore automatically know how to interpret the data it receives from those devices. Any address could conceivably be used by any number of non-related devices, and with devices where the user can modify parts of the address itself, those devices could have any of a range of addresses. Therefore when using I2C Linux can help you with the minutiae of sending and receiving individual data packets, but knowing which devices are in use and how to interpret their data is up to you.</p><h4 style="text-align: left;">1-Wire</h4><p style="text-align: left;">As we've already seen, the DS18B20 is one of the simplest devices to use with the RaspberryPi; wire it up, and read its temperature. No extra circuitry required, no fancy conversions. But the fact it uses the 1-wire protocol gives us a couple additional benefits as well.</p><p style="text-align: left;">As part of the 1-wire protocol, any device that uses the 1-wire protocol must have a 64-bit unique serial ID (address) burned into it from the factory. The first 8-bits of this 64-bit number identify the device class, which is centrally administered in order to avoid address collisions. A centrally-administered database of device classes means that OSes, like Linux, can uniquely identify what type of device is connected, and can therefore know how to present its data. The DS18B20's class ID is 0x28, therefore any time Linux detects a 0x28 device connected to it via 1-wire, it knows this is a DS18B20 and can dynamically create a file in sysfs that presents user-space with a simple temperature reading. 1-wire buses are <i>discoverable</i>.</p><p style="text-align: left;">The other advantage of the 1-wire protocol (made possible as a consequence of the unique 64-bit number burned into every device at the factory) is its ability to enumerate all such devices attached to a single bus. Due to the low-speed nature of the bus, and various other electrical properties, 100s (if not 1000s) of devices can be connected together on 1 GPIO pin; all uniquely addressable, and all able to report their unique temperature reading to the user.</p><h4 style="text-align: left;">Multiple Sensors Conclusion</h4><p style="text-align: left;">If you want to connect only one sensor to your device, any sensor using any bus will do. Once you get between 2 and 8, you'll probably want to drop SPI and try either I2C (if your device has 3 address pins) or 1-wire. But once you getting up into the 6 range, and certainly past 8, you'll want to switch to 1-wire and use the DS18B20. Also, SPI and I2C are buses that are designed for on-device, short range communication; they are not buses that can accommodate placing sensors a significant distance away from the SBC itself.</p><p style="text-align: left;">Therefore, for designs where multiple sensors need to be spread out in an area but preferably connected to one SBC, the DS18B20 has many advantages:</p><p style="text-align: left;"></p><ul style="text-align: left;"><li>the 1-wire bus is a long-distance bus that can let you connect sensors that are several metres away from your SBC</li><li>the DS18B20 has a wide temperature range, and high accuracy</li><li>the DS18B20 comes in several form-factors, one of which is in a temperature-appropriate and water-proof housing</li><li>you can connect 100s of them up reliably to a single RaspberryPi or other SBC</li><li>due to their unique serial numbers with a centrally-managed device prefix, Linux (and other OSes) are able to know what devices are connected to them (they're <i>discoverable</i>) and therefore do all the conversions internally for you, presenting user-space with a simple file to read containing each device's temperature (one file per device) automatically</li></ul><div>Specific details of using a DS18B20 can be found <a href="https://twoerner.blogspot.com/2020/12/temperature-readings-with-ds18b20-and.html" target="_blank">in another one of my posts</a>. Using multiple DS18B20s at a time is discussed <a href="https://twoerner.blogspot.com/2020/12/multiple-ds18b20-temperature-probes.html" target="_blank">in the post at this link</a>.</div><p></p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-68480856584808037112021-01-17T21:56:00.009-05:002022-03-21T08:45:02.242-04:00Sensing Temperature with a RaspberryPi<p>Devices for sensing temperature in electronics projects come in 3 basic varieties:</p><p></p><ol style="text-align: left;"><li>resistive sensors</li><li>thermometer ICs</li><li>digital thermometers</li></ol><div>In this blog post I'll discuss the first variety. Future posts will discuss the others.</div><div><br /></div><h2 style="text-align: left;">Resistive Sensors</h2><h4 style="text-align: left;">Thermistor</h4><p style="text-align: left;">The thermistor is the most basic, and cheapest, way to detect temperature. A thermistor is a 2-lead device whose resistance at any given point in time is directly related to its temperature at that time.</p><p style="text-align: left;">Thermistors come in 2 varieties:</p><p style="text-align: left;"></p><ul style="text-align: left;"><li>PTC (<b>p</b>ositive <b>t</b>emperature <b>c</b>oefficient)</li><ul><li>resistance increases with increasing temperature</li></ul><li>NTC (<b>n</b>egative <b>t</b>emperature <b>c</b>oefficient)</li><ul><li>resistance decreases with increasing temperature</li></ul></ul><p style="text-align: left;">NTC-type thermistors are the most common.</p><p style="text-align: left;">In reality all electronic components (especially resistors) are affected by temperature, but ideally the effects due to temperature are minimal. In most cases the effects are so small that trying to use a regular resistor to measure temperature would require sensitive measuring devices and amplification in order to detect the variances. It could only be used as a very crude temperature sensing device with little resolution. A thermistor is specifically designed to highlight the effects of temperature and to make these effects noticeable in response to relatively small temperature changes.</p><p style="text-align: left;">One major challenge with using a thermistor is that the relationship between resistance and temperature is not linear across a temperature range. Pretend you have a thermistor that at 0°C was 1kΩ and at 10°C was 2kΩ, meaning there's a 1kΩ change for every 10°C. That doesn't mean that if the resistance at 40°C is XkΩ that the resistance at 50°C will be (X+1)kΩ. The change might be (X+7) or (X+0.4).</p><p style="text-align: left;">Figuring out how to translate between measured resistance and temperature can require a tricky bit of math! A commonly accepted relationship between resistance and temperature is given by the <a href="https://en.wikipedia.org/wiki/Thermistor#Steinhart%E2%80%93Hart_equation" target="_blank">Steinhart-Hart Equation</a>:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-MXC0B9MvZZc/YANYGWeb1eI/AAAAAAAAlGg/SnDvAGtASNMOD-3nRNguU2qx58qLFKwSgCLcBGAsYHQ/s489/equ.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="123" data-original-width="489" src="https://1.bp.blogspot.com/-MXC0B9MvZZc/YANYGWeb1eI/AAAAAAAAlGg/SnDvAGtASNMOD-3nRNguU2qx58qLFKwSgCLcBGAsYHQ/s16000/equ.png" /></a></div><p style="text-align: left;">For this equation the temperature is specified in Kelvins, and you need to know the <i>a</i>, <i>b</i>, and <i>c</i> coefficients for your specific thermistor in order to use this equation. The datasheet for a thermistor will go into a lot of detail to help explain how to perform the translation and will often provide these coefficients for you (or coefficients for other equations it provides). This third-order equation wouldn't be too hard for a RaspberryPi to perform, but a lookup table with linear interpolation would probably work better in practice (especially for math-challenged SoCs such as 8-bitters).</p><p style="text-align: left;">Another issue faced with thermistors is their susceptibility to self-heating. Any electronic circuit will tend to heat up when it is powered; thermistors are no exception. However, given that the job of this device is to measure temperature, heating up as a result of being powered on will cause a thermistor to report a slightly higher temperature than its surroundings. Again, a datasheet provides the details for how to account for this effect mathematically.</p><p style="text-align: left;">Although we're now aware of various issues that can cause our measurement to require correcting, we still haven't figured out how to use a RaspberryPi to measure the resistance of a thermistor.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-6yskOSfFvXw/YANb7_HW9JI/AAAAAAAAlGw/YtPF4ZHc9R8EZdAE2S3dAd-hprIhtoolQCLcBGAsYHQ/s1266/rpi-thermistor.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="592" data-original-width="1266" height="299" src="https://1.bp.blogspot.com/-6yskOSfFvXw/YANb7_HW9JI/AAAAAAAAlGw/YtPF4ZHc9R8EZdAE2S3dAd-hprIhtoolQCLcBGAsYHQ/w640-h299/rpi-thermistor.png" width="640" /></a></div><h4 style="text-align: left;">Analog-to-Digital Converters</h4><p style="text-align: left;">If we take a step back, we'll realize that a varying resistance is an analog signal. One of the best ways to measure an analog signal is to use an <a href="https://en.wikipedia.org/wiki/Analog-to-digital_converter" target="_blank">analog-to-digital converter</a> (ADC): a circuit whose job it is to measure analog signals and convert them into 1s and 0s for digital processing.</p><p style="text-align: left;">The problem is that an ADC measures voltage, not resistance. Therefore we need a way to convert a varying resistance into a varying voltage. Luckily this problem isn't too hard to solve: some sort of voltage divider circuit can be easily constructed for this purpose.</p><p style="text-align: left;">A second issue is that the RaspberryPi doesn't have (or doesn't expose) any ADCs for our use. Most SoCs have at least one ADC which the SBC exposes through its interface header. This is especially true of boards that are targeted at this market (i.e. the "maker" space or educational electronics). The standard Arduino, for example, has 6 analog pins. It's possible, however, that not having an available ADC might be a good thing. There are tens of thousands of discrete ADC ICs from which to choose (hundreds that are through-hole alone). One can choose the resolution (i.e. the number of bits) from 6 to 32, the communication protocol (e.g. I2C, SPI, QSPI, parallel, 1-wire, serial, etc and combinations thereof), the sampling rate (from as low as a couple samples a second up to over 10G S/s), the voltage ranges you want to sample, the signal-to-noise ratio, and the type/architecture of the conversion circuitry. When an ADC is integrated into the SoC, the ADC that is chosen will be a general-purpose one with middle-of-the-road (or below) specs. Being able to choose the right ADC for your application might be a good thing.</p><p style="text-align: left;">Now we have all the pieces we need in order to use a thermistor with a RaspberryPi to read temperature:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ZIFijZhj1Bw/YARg2T61iLI/AAAAAAAAlH8/CjmwtRYNAQ87eLSa0EmF6HFRRKy7_1O3QCLcBGAsYHQ/s1249/rpi-adc-vdivider-thermistor.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="584" data-original-width="1249" height="300" src="https://1.bp.blogspot.com/-ZIFijZhj1Bw/YARg2T61iLI/AAAAAAAAlH8/CjmwtRYNAQ87eLSa0EmF6HFRRKy7_1O3QCLcBGAsYHQ/w640-h300/rpi-adc-vdivider-thermistor.png" width="640" /></a></div><p style="text-align: left;">Note that the components in the drawing are not drawn to scale, and that the voltage divider drawing is meant to be a generic representation of a voltage divider circuit, although perhaps not the exact circuit that is needed. I chose the MCP3001 as my ADC simply because when I looked through the drawer of ADC components I have on my workbench, that's one of the ones I found. It happens to be a 1-channel ADC that uses SPI for communication, has 10 bits of resolution, and has a sampling rate of 75kS/s at 2.7V (or 200kS/s at 5V).</p><p style="text-align: left;">The thermistor forms one of the loads of the voltage divider. The output of the divider is fed to the IN+ pin of the ADC (pin 2). Pins 5, 6, and 7 of the ADC are the SPI pins that are hooked up to the RaspberryPi. +3.3V and grounds are hooked up as appropriate.</p><p style="text-align: left;">Our circuit is ready to read temperature. Now on to the software.</p><h4 style="text-align: left;">Communication Buses</h4><p style="text-align: left;">Before we can get on with the job of reading the converted voltage values from the ADC over SPI, we need to take a quick look at communication buses in general.</p><p style="text-align: left;">If you want to connect two or more computers together in the same building, chances are you'd use Ethernet, WiFi, or maybe TokenRing: these are the common communication buses used between personal computing devices. Expansion cards on a motherboard are often connected via ISA, PCI, and/or PCIe buses. External devices are often connected to a personal computer with some version of USB.</p><p style="text-align: left;">In the embedded world, two of the most common inter-chip communication buses are I2C and SPI; these are two (mostly) standardized ways of connecting individual components together on a PCB. Like all good specifications, the design of the I2C and SPI buses define aspects such as the signaling, what to do in case of a collision, the algorithm of which devices get to speak when, the data rate(s), if/how multiple devices can be connected at the same time, and how to physically connect devices together (how many pins and wires are needed).</p><p style="text-align: left;">As we've just seen, we found ourselves in the position where we needed to add a discrete IC to our design (i.e. the ADC). In theory every chip could define its own communication method(s), or every company could define its own communication protocols for the devices it manufactures. There is much benefit to the end user if manufacturers standardize on a small set of common protocols.</p><p style="text-align: left;">Some buses are <i>discoverable</i>. This means there is a mechanism devices can use to identify themselves uniquely and/or specify which generic service they provide. The PCIe and USB buses are discoverable. Without any intervention from the user, the OS is able to identify each connected device, and get them ready to be used. For example, if the user plugs an external hard-drive into a computer's USB bus, the OS (if instructed to do so) can automatically mount one or more of the hard-drive's partitions into the filesystem. This requires anyone wanting to create and sell PCIe or USB devices to buy, and pay a yearly fee, in order to own a unique vendor ID.</p><p style="text-align: left;">I2C and SPI buses are not discoverable. There is no way for an OS (or RTOS) to probe these buses and be sure they've uniquely found all connected devices. Therefore it is not possible for Linux (for example) to generate sysfs entries for devices connected on these buses and perform various conversions automatically. Which means that if you want to read an ADC over SPI (or I2C) you'll need to write your own software (or find ready-to-use libraries from someone who has already written them).</p><h4 style="text-align: left;">SPI</h4><p style="text-align: left;">Before you can write software to interact with an SPI-connected device, you have to understand a few things about how SPI works. SPI defines a clock line, and 2 data lines (one in each direction). It uses a physical chip select line to select which slave device can respond to the master.</p><p style="text-align: left;">When a slave device writes to the bus, it will make its data valid on either the rising or falling edge of the clock. The clock line (which is controlled by the master) can either idle high or idle low when not in use. The master and slave have to agree on these parameters of the communication in order for them to communicate successfully. Defining which way the clock line idles is generally referred to as the CPOL, or clock polarity. Defining whether the data is valid on the rising or falling clock edge is generally referred to as the CPHA, or clock phase.</p><p style="text-align: left;">The datasheet for your specific SPI device will tell you which combinations of (CPOL, CPHA) the device supports. The MCP3001, for example, only supports configurations (0, 0) and (1, 1).</p><p style="text-align: left;">The SPI bus supports a range of data rates, but not all devices support all possible data rates. The data rate is related to the sampling rate; there wouldn't be much use in a high sampling rate if there was no way to send that data to the master in time. Again, consult the datasheet for your device to know which data rates can be safely used; the MCP3001 supports data rates up to 2.8MHz.</p><p style="text-align: left;">The last piece of information you need to know is the data format. The MCP3001 is a single-channel, 10-bit ADC. In theory 10 bits of data could be transferred using 10 bits. However Linux seems to prefer to communicate using 8-bit bytes. My attempts to change the bit size from 8 to 10 weren't successful; possibly a driver issue. In any case I was forced to communicate with the MCP3001 using 8-bit packets. For reasons that aren't entirely clear, when the MCP3001 detects that 8-bit bytes are being used for communication, it encodes its 10 bits of data as follows:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-KAOtMz1S02E/YASIBduNYAI/AAAAAAAAlIg/IDZqhvMPp20mp7__J5BOVUbW8erdCY3HwCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="110" data-original-width="727" height="97" src="https://lh3.googleusercontent.com/-KAOtMz1S02E/YASIBduNYAI/AAAAAAAAlIg/IDZqhvMPp20mp7__J5BOVUbW8erdCY3HwCLcBGAsYHQ/w640-h97/image.png" width="640" /></a></div><br />The act of initiating a read from the device is what causes the conversion to commence. Therefore the first three bits from the device are two unknowns (X) and a 0 due to the time required to perform a conversion. Next the device starts writing the 10 bits starting with the MSb. Once it reaches the LSb it then writes these same bits out again going from the LSb to the MSb. Any bits that are read after these 22 bits, are read as zeros.<p></p><p style="text-align: left;">Knowing these parameters for your specific SPI device, you can now write the code to communicate with your device over SPI.</p><h4 style="text-align: left;">OpenEmbedded/Yocto</h4><p style="text-align: left;">Before you can use SPI on your RaspberryPi, you have to enable it. Enabling SPI on the RaspberryPi requires the user to modify the contents of the config.txt file (correctly) and reboot. If you're using any images or distros that are not based on OpenEmbedded/Yocto then there are a bunch of different tools and ways to modify this file (including using a simple text editor). If you don't make your edits correctly you could end up with a device that refuses to boot until you correct any problems.</p><p style="text-align: left;">If you are using OpenEmbedded/Yocto to generate your images, enabling SPI is as simple as adding the following line to your configuration (most likely your conf/local.conf file):</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-D4krJPFKq-Y/YASLLbKjWCI/AAAAAAAAlIs/sVcMIBKC6IsgVB9zpt9ODYZ4bqSpfCtSACLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="106" data-original-width="720" height="47" src="https://lh3.googleusercontent.com/-D4krJPFKq-Y/YASLLbKjWCI/AAAAAAAAlIs/sVcMIBKC6IsgVB9zpt9ODYZ4bqSpfCtSACLcBGAsYHQ/w320-h47/image.png" width="320" /></a></div><p></p><p style="text-align: left;">I can't imagine anything simpler. Rebuild your image, flash it to your µSD card, and boot.</p><h4 style="text-align: left;">SPI in Linux on RPi</h4><p style="text-align: left;">Writing code for Linux to read an SPI device in user-space is very straight-forward, provided you've read the datasheet of your device and you know how it needs to be configured (i.e. which SPI mode(s) it uses, the bit size, and speed) and the format of the data it will give you.</p><p style="text-align: left;">If your image is setup correctly with SPI enabled, after your device boots you'll find the following device nodes in your filesystem:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">#</span> ls -l /dev/spidev*
<span style="color: #777777;">crw------- 1 root root 153, 0 Jan 1 1970 /dev/spidev0.0</span>
<span style="color: #777777;">crw------- 1 root root 153, 1 Jan 1 1970 /dev/spidev0.1</span>
</pre></div>
<p style="text-align: left;">Your device will be connected to one of these nodes. Simply write a program that opens the correct one, uses ioctl(2)s to configure it, and read(2)s from it to get data from your SPI device.</p><p style="text-align: left;">The RaspberryPi's 40-pin GPIO Header exposes one SPI bus with two chip selects:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-dK1-xP0u8Xg/YASoKKWbJyI/AAAAAAAAlJU/RKKvy8lJ_RIQHpSUWOhQmh6xqP_6VHcAgCLcBGAsYHQ/s2700/Raspberry-Pi-GPIO-Layout-Model-B-Plus-rotated-2700x900.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2700" data-original-width="900" height="640" src="https://1.bp.blogspot.com/-dK1-xP0u8Xg/YASoKKWbJyI/AAAAAAAAlJU/RKKvy8lJ_RIQHpSUWOhQmh6xqP_6VHcAgCLcBGAsYHQ/w214-h640/Raspberry-Pi-GPIO-Layout-Model-B-Plus-rotated-2700x900.png" width="214" /></a></div><p style="text-align: left;">Connect the MCP3001's Pin-6 (D<sub>OUT)</sub> to the RPi's Pin-21 (SPI0_MISO), connect MCP3001's Pin-7 (CLK) to RPi's Pin-23 (SPI0_SCLK). If you connect MCP3001's Pin-5 (/CS) to RPi's Pin-24 (SPI0_CE0_N) then your device will be at /dev/spidev0.0. If, instead, you connect the MCP3001's chip-select to RPi's Pin-26 (SPI0_CE1_N) then you'll find your device at /dev/spidev0.1. This is how you know which device to use in your code. In the string "spidevX.Y" the X refers to the SPI bus, and the Y refers to the chip-select for SPI bus X.</p><p style="text-align: left;">You'll notice that since the MCP3001 is a 1-channel ADC, it doesn't receive any commands from the master. In fact, it doesn't even have a MOSI data line (<b>m</b>aster <b>o</b>ut, <b>s</b>lave <b>i</b>n), it only has a D<sub>OUT</sub> data line (aka MISO). Therefore there's nothing to connect to the RPi's Pin-19 (SPI0-MOSI) pin. Most other SPI devices would have something connected to this pin.</p><p style="text-align: left;">Now that you've open(2)ed the correct device, you can proceed to configure it with various SPI ioctl(2)s. You can set the mode with <b><i>SPI_IOC_WR_MODE32</i></b>, you set the number of bits with <b><i>SPI_IOC_WR_BITS_PER_WORD</i></b>, and you set the speed with <b><i>SPI_IOC_WR_MAX_SPEED_HZ</i></b>. The <a href="https://elixir.bootlin.com/linux/latest/source/Documentation/spi/spidev.rst" target="_blank">Linux kernel's SPI documentation</a> provides lots of information, or you can just <a href="https://elixir.bootlin.com/linux/v5.10.7/source/include/linux/spi/spi.h#L109" target="_blank">read the source code itself</a>.</p><p style="text-align: left;">I've written a small MCP3001 program (<a href="https://github.com/twoerner/mcp3001" target="_blank">which you can find here</a>) to demonstrate. The defaults are all setup to work "out-of-the-box" (assuming you're using /CS0). Otherwise the program takes a range of optional cmdline arguments that can be used to tweak the configuration.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">#</span> mcp3001 -h
<span style="color: #777777;">mcp3001 1.0.0</span>
<span style="color: #777777;">usage: mcp3001 [options]</span>
<span style="color: #777777;"> where:</span>
<span style="color: #777777;"> options:</span>
<span style="color: #777777;"> -D|--device <d> SPI device to use (default: /dev/spidev0.0)</span>
<span style="color: #777777;"> -s|--speed <s> max speed (Hz)</span>
<span style="color: #777777;"> -b|--bpw <b> bits per word</span>
<span style="color: #777777;"> -O|--cpol clock polarity, idle high (default: idle low)</span>
<span style="color: #777777;"> -H|--cpha clock phase, sample on trailing edge (default: leading)</span>
<span style="color: #777777;"> -L|--lsb least significant bit first</span>
<span style="color: #777777;"> -C|--cs-high chip select active high</span>
<span style="color: #777777;"> -3|--3wire SI/SO signals shared</span>
<span style="color: #777777;"> -N|--no-cs no chip select</span>
<span style="color: #777777;"> -R|--ready slave pulls low to pause</span>
<span style="color: #777777;"> -v|--verbose add verbosity</span>
<span style="color: #777777;"> -V|--version print version</span>
</pre></div>
<h4 style="text-align: left;"><br /></h4><h4 style="text-align: left;">A Thermistor and a RaspberryPi</h4><p style="text-align: left;">At this point we have everything we need to read a temperature with a RaspberryPi using a thermistor: in addition to the RPi and a thermistor we have an ADC which can read the analog signal and convert it to binary, and we have a voltage divider circuit which converts a varying resistance to a varying voltage which the ADC can measure. We have SPI enabled in our image, we have our ADC device hooked up to our RPi, and we even have some code to read the values being generated by the ADC over SPI.</p><p style="text-align: left;">As you can see, reading a temperature of a thermistor with a RaspberryPi is not very straight-forward; despite the information in this post, more work remains. I glossed over the math parts because, frankly, it's not worth it. Also, I didn't dig very deeply into the details of the voltage divider circuit needed to convert the varying resistance to a varying voltage. As we'll see in subsequent posts, there are much easier ways (and, ironically, much more accurate ways) to read a temperature.</p><h4 style="text-align: left;">Nothing Wasted</h4><p style="text-align: left;">The good news is: time spent learning something new is never wasted.</p><p style="text-align: left;">Although the details needed to use a thermistor aren't really worth the effort, the things we've learned are applicable to a great many other situations. There are a number of sensors that measure something in the physical world, and describe it using a varying resistance.</p><p style="text-align: left;">For example: a user rotating a dial on a potentiometer changes the amount of resistance. A photocell changes its resistance based on how much light falls on it. Force sensitive resistors change their resistance based on how hard they are being pressed. Also, 2-axis analog joysticks don't just report that their toggle has been moved (for example) to the left, they provide a set of resistors that are read to indicate how far along each of the X and Y planes the toggle has been moved.</p><p style="text-align: left;">Everything we've learned hooking up a thermistor to a RaspberryPi can be used to read a whole host of other sensors!</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-4-dzshcQx4M/YATzkHZsClI/AAAAAAAAlJ8/3zHGggr38-MJyKtrG9Rp9xedB2hUdusIQCLcBGAsYHQ/s1348/other-resistor-sensors.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="743" data-original-width="1348" height="352" src="https://1.bp.blogspot.com/-4-dzshcQx4M/YATzkHZsClI/AAAAAAAAlJ8/3zHGggr38-MJyKtrG9Rp9xedB2hUdusIQCLcBGAsYHQ/w640-h352/other-resistor-sensors.png" width="640" /></a></div><p style="text-align: left;"><br /></p><p></p><p></p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-57938531035126888192021-01-08T17:42:00.020-05:002022-03-21T08:44:57.017-04:00Device Enumeration on a 1-Wire Bus<h3 style="text-align: left;">Introduction</h3><p>In my <a href="https://twoerner.blogspot.com/2020/12/temperature-readings-with-ds18b20-and.html" target="_blank">last</a> <a href="https://twoerner.blogspot.com/2020/12/multiple-ds18b20-temperature-probes.html" target="_blank">two</a> posts I discussed using a DS18B20 to obtain the temperature. In digital electronics, most IC devices would use either the <a href="https://en.wikipedia.org/wiki/I%C2%B2C" target="_blank">I<sup>2</sup>C</a> protocol or the <a href="https://en.wikipedia.org/wiki/Serial_Peripheral_Interface" target="_blank">SPI</a> protocol for communication. The DS18B20 temperature sensor, however, uses the <a href="https://en.wikipedia.org/wiki/1-Wire" target="_blank">1-wire</a> protocol; a standard, though less common, protocol. While reading the datasheet for the DS18B20, one thing that fascinated me about the 1-wire protocol is its algorithm for correctly detecting an arbitrary number of connected devices despite having only one, bi-directional data wire and despite all these data wires being connected together in one big node.</p><p>On twitter I <a href="https://twitter.com/TrevorWoerner/status/1343954956164980736" target="_blank">jokingly lamented</a> the fact that the Linux kernel already has full support for the 1-wire protocol as well as the DS18B20, thus "robbing" me of the opportunity to learn much about either in detail. Therefore in order to "buy back" some of this opportunity, I decided to write my own code (in userspace) implementing the 1-wire device discovery algorithm. This exercise also forced me to write the code for a "testing" application which mimics the behaviour of an arbitrary number of connected devices.</p><p>The project consists of 2 parts:</p><p></p><ul style="text-align: left;"><li>the ROMsearch program which acts as the "master" side of the algorithm, and implements the ROMsearch feature of the 1-wire protocol</li><li>a tester component which either reads in pre-crafted files or generates random data and acts as a representation of an arbitrary number of connected "devices"</li></ul><p></p><p>The two programs communicate with each other over a pair of fifos, which act as the "wiring" of the circuit. The code for this project can be found in the <a href="https://github.com/twoerner/ROMsearch" target="_blank">ROMsearch repository of my github profile</a>.</p><h3 style="text-align: left;">Algorithm</h3><p>I encourage you to read the specification yourself for the exact details. The datasheet I'm using can be found <a href="https://image.dfrobot.com/image/data/DFR0198/DS18B20.pdf" target="_blank">here</a>. There are also other places where the 1-wire device discovery algorithm is described such as <a href="https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/187.html" target="_blank">here</a> and <a href="https://www.maximintegrated.com/en/design/technical-documents/app-notes/9/937.html" target="_blank">here</a>.</p><p>Every specification sits atop a set of assumptions and facts in order for it to function correctly. Here are the relevant facts and assumptions related to this algorithm:</p><p></p><ul style="text-align: left;"><li>Each device comes from the factory with a unique 64-bit serial number encoded into its ROM.</li><li>All data is transmitted LSb first.</li><li>The master initiates all conversations.</li><li>Multiple devices are permitted to write to the bus at the same time.</li><li>The data line (DQ) has a weak pullup, as a consequence of the weak pullup on DQ:</li><ul><li>if all devices write a 1 at the same time, the master reads 1 on DQ</li><li>if all devices write a 0 at the same time, the master reads 0 on DQ</li><li>if 1 or more devices write a 1, and 1 or more devices write a 0 on DQ at the same time, the master reads a 0 on DQ (regardless of the number of devices writing a given value versus the other)</li><li>if there are no devices trying to write anything to DQ, the master will read a 1</li></ul></ul><p>Interestingly enough, this algorithm and the circuitry of the 1-wire bus, are designed to expect multiple devices to write to the bus at the same time. Usually much care is taken in the design of a shared bus to make sure that no two devices ever try to write to the bus at the same time; and to detect when such inevitable events occur. In the case of a 1-wire system, having multiple devices write to the bus at the same time is a feature, and an integral part of the algorithm's success.</p><p>The gist of the algorithm is as follows:</p><p></p><ul style="text-align: left;"><li>the master issues a RESET on the line, this causes all devices to enter their reset state</li><li>the master sends the ROMsearch command on the line putting all devices into ROMsearch mode; this causes all devices to get ready to send their serial numbers starting with the LSb</li><li>the master issues a read on the line, all devices put the first bit of their respective serial numbers on the data line simultaneously; the master records this value</li><li>the master then issues a second read on the line, all devices put the complement of the first bit of their respective serial numbers on the line, the master records this value too</li><li>the master then writes either a 0 or a 1 on the data line; any device whose current actual bit matches the value put on the line by the master will continue being part of the search; any device whose current actual bit doesn't match the value put on the line by the master will stop responding to the master until a RESET is seen</li><li>all of the devices that are still part of the search get ready to put the next bit, and its complement, on the data line as the master issues two more reads</li><li>this pattern (2 reads, 1 write) continues until an entire serial number is read, then the whole sequence starts again in an effort to find the next device's serial number (if any are left to discover)</li></ul><p style="text-align: left;">The algorithm assumes that all devices are able to stay in sync. In other words, for any given pass through the search algorithm (i.e. the set of 2 reads and a write from the master) all slave devices are working on the same bit position. In other words, in the first pass they are all sending their 0th bit… on the 11th pass they're all sending their 10th bit, etc. The algorithm wouldn't work if one device was sending its 12th bit while another was sending its 5th.</p><p></p><p>Due to the rules of boolean logic, the "bit and complement" nature of the algorithm, and the fact that all the writes from the devices are logically ANDed together (due to the pull-up circuitry of the 1-wire bus, as described above) the master can interpret each pair of values it reads on the line as follows:</p><p></p><ul style="text-align: left;"><ul><li>01: all devices still part of the search have a 0 in the current bit position</li><li>10: all devices still part of the search have a 1 in the current bit position</li><li>00: some of the devices have a 1, others have a 0 in the current bit position</li><li>11: there are no devices responding as part of the search (we've reached the end of the serial number)</li></ul></ul><p></p><h3 style="text-align: left;">Example</h3><p style="text-align: left;">It's time to look at a concrete example. For this example we're going to limit the length of the serial number to 8 bits. In this example there are 4 devices on the bus whose serial numbers are:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-jKzxv0aZI54/X_igwj2Xc1I/AAAAAAAAk4U/d9a2wvREeyY927q1c0f-afTV72RZG6WtgCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-jKzxv0aZI54/X_igwj2Xc1I/AAAAAAAAk4U/d9a2wvREeyY927q1c0f-afTV72RZG6WtgCLcBGAsYHQ/s16000/image.png" /></a></div><br />Starting with a reset and ROM-search command, all devices are in ROM-search mode and are ready to send the 1st bit of their respective serial numbers. The master performs a read on the data line and all devices send their 1st bit at the same time. This results in a 0 being read by the master.<p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-EvcFGdqOCAU/X_iick7QDGI/AAAAAAAAk4s/cBn2OOu1piIaEJOEvskrMfb45OvVQo_BgCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-EvcFGdqOCAU/X_iick7QDGI/AAAAAAAAk4s/cBn2OOu1piIaEJOEvskrMfb45OvVQo_BgCLcBGAsYHQ/s16000/image.png" /></a></div><br />The master performs a second read and all devices write the complement of their 1st bit at the same time. The master records a 1:<p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-Fq40JeMT31g/X_iilXFEi1I/AAAAAAAAk4w/3VGU2EZNyjoWJ-PH05XeyzT21HssU2UqQCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-Fq40JeMT31g/X_iilXFEi1I/AAAAAAAAk4w/3VGU2EZNyjoWJ-PH05XeyzT21HssU2UqQCLcBGAsYHQ/s16000/image.png" /></a></div><br />The master has no idea how many devices are connected on the bus, but it does know that this bit of all devices is a 0, because it did not encounter a fork. The master adds a 0 to the serial number it is currently creating:<p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-0e91RtdbIQY/X_ijNerdOrI/AAAAAAAAk5A/2aODMThSiWAu867w5f0wGjBNd7IWUuURQCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-0e91RtdbIQY/X_ijNerdOrI/AAAAAAAAk5A/2aODMThSiWAu867w5f0wGjBNd7IWUuURQCLcBGAsYHQ/s16000/image.png" /></a></div><br />The master writes a 0 on the data line, all devices who have a 0 bit in the current position remain part of the search (which in this case is all of them).<p></p><div><p style="text-align: left;">Having written a 0 on the data line causes all the devices to move on to their 2nd bit. The same thing happens for the 2nd bit. The master performs two reads on the data line which causes all devices still part of the search to write their 2nd bit and its complement (respectively) on the bus in response to each read pulse. Since all devices, coincidentally, have a 0 in their 2nd bit as well, the master sees another 01, adds a 0 to the serial number it is building, writes a 0 on the data line, and all devices continue to be part of the search:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-RmOH4ewP7zY/X_ijsCwL0wI/AAAAAAAAk5I/F-9JL_n2Fk4BJYoLkujjG5GFciey5Sn-wCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-RmOH4ewP7zY/X_ijsCwL0wI/AAAAAAAAk5I/F-9JL_n2Fk4BJYoLkujjG5GFciey5Sn-wCLcBGAsYHQ/s16000/image.png" /></a></div><br />Now we move to the 3rd bit. The first read yields the following bits. When they're all written to the bus at the same time the master reads a 0:<p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-jQse_QPtaSA/X_ikNeSLOuI/AAAAAAAAk5U/5RKQhdheoRgwc-DBXSyYLUPxeNOUaMW0gCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-jQse_QPtaSA/X_ikNeSLOuI/AAAAAAAAk5U/5RKQhdheoRgwc-DBXSyYLUPxeNOUaMW0gCLcBGAsYHQ/s16000/image.png" /></a></div><br /><p style="text-align: left;">When all devices write the complement of the 3rd bit of their serial number on the bus the master reads another 0:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-AFUb2jKPDZI/YADJMXChpDI/AAAAAAAAlEQ/NcGhOlskNPI534LCDtllTlrHQs999U4jQCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-AFUb2jKPDZI/YADJMXChpDI/AAAAAAAAlEQ/NcGhOlskNPI534LCDtllTlrHQs999U4jQCLcBGAsYHQ/s16000/image.png" /></a></div><br />Now that the master has seen a 00 it knows that at this bit position (i.e. the 3rd bit position) there is a fork: there is at least one device with a serial number of (in part) "000" and there is at least one device with a serial number that begins with "100". The master needs to continue down one path, while remembering to come back and finish the other path. Which path it chooses to finish now is irrelevant.<p></p></div><div><p></p><p style="text-align: left;">Let's arbitrarily decide to finish the 0 path now. In doing so, we need to save the partial serial number "100" for later, add a 0 to the current serial number we're building, and write a 0 to the data line.</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-YmgLtL0NsXQ/YADJCf6F_9I/AAAAAAAAlEM/QC80kMnD1TUD1GDFt7uU8FW_rMZXW7rOQCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-YmgLtL0NsXQ/YADJCf6F_9I/AAAAAAAAlEM/QC80kMnD1TUD1GDFt7uU8FW_rMZXW7rOQCLcBGAsYHQ/s16000/image.png" /></a></div><br /><p></p><p style="text-align: left;">Writing a 0 to the data line at this point eliminates devices #1 and #4 from the search. With these two devices eliminated, the next set of reads yields:</p><p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-e3WAdV8RvNc/X_imGINSp7I/AAAAAAAAk5s/FHpwtYJQLpgt9sgQnZdC6yfbEFNSyoecwCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-e3WAdV8RvNc/X_imGINSp7I/AAAAAAAAk5s/FHpwtYJQLpgt9sgQnZdC6yfbEFNSyoecwCLcBGAsYHQ/s16000/image.png" /></a></div><br />A 01 lets the master know that all remaining devices have a 0 at the current position. Therefore it writes a 0 to the bus, which keeps both remaining devices in the search, and adds a 0 to the serial number it is building:<p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-XpkpZIV7qfE/X_imlFpdgCI/AAAAAAAAk54/rv5lYcmM1M0MjRYVr4a-nKsSde0VCy_bQCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-XpkpZIV7qfE/X_imlFpdgCI/AAAAAAAAk54/rv5lYcmM1M0MjRYVr4a-nKsSde0VCy_bQCLcBGAsYHQ/s16000/image.png" /></a></div><br />This process continues with the 5th bit of the remaining devices. Seeing a 10 in response to a set of reads lets the master know the next bit of all remaining devices is a 1:<p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-CGR678fiD8U/X_inbqcFITI/AAAAAAAAk6I/A6T4dTzg3XomPknQWkt9Yeg30qocIBxhgCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-CGR678fiD8U/X_inbqcFITI/AAAAAAAAk6I/A6T4dTzg3XomPknQWkt9Yeg30qocIBxhgCLcBGAsYHQ/s16000/image.png" /></a></div><br /><p></p><p style="text-align: left;">The 6th bit:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-U8rjrfn8_3U/X_io9ggIU-I/AAAAAAAAk6U/aL-qC2icEd82l2vnpUloRIt7ZsuqJdYjACLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-U8rjrfn8_3U/X_io9ggIU-I/AAAAAAAAk6U/aL-qC2icEd82l2vnpUloRIt7ZsuqJdYjACLcBGAsYHQ/s16000/image.png" /></a></div><br />At the 6th bit position of all the devices that are remaining along the 0 fork from the last time we encountered a 00, we have found another fork. If we arbitrarily decide to take the 0 fork again at this junction then, in addition to remembering to finish the "100" fork we found earlier, we also have to remember to finish the "110000" that we've just found now.<p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-roqqlrBbKZM/X_iprO67Y6I/AAAAAAAAk6c/KvH0m1KS1pIxdY9J4JYVFgVGD3eOIH-pwCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-roqqlrBbKZM/X_iprO67Y6I/AAAAAAAAk6c/KvH0m1KS1pIxdY9J4JYVFgVGD3eOIH-pwCLcBGAsYHQ/s16000/image.png" /></a></div><br />Taking the 0 fork again removes device #3 from the list:<p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-0uDGL9T6Oyk/X_iqKA53qpI/AAAAAAAAk6k/Cnfrxnw_9zovnq1EQd4Ce2ufWXpQN_I8ACLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-0uDGL9T6Oyk/X_iqKA53qpI/AAAAAAAAk6k/Cnfrxnw_9zovnq1EQd4Ce2ufWXpQN_I8ACLcBGAsYHQ/s16000/image.png" /></a></div><p></p></div><div><p style="text-align: left;">Performing 2 reads yields:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-OpL0bZOONyg/X_iqnW2cIOI/AAAAAAAAk6s/RcyF27vEQKsm4vMtVZi2v1MV44CWK3C3ACLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-OpL0bZOONyg/X_iqnW2cIOI/AAAAAAAAk6s/RcyF27vEQKsm4vMtVZi2v1MV44CWK3C3ACLcBGAsYHQ/s16000/image.png" /></a></div><br />Which we know means that all remaining devices have a 1 in the current position. Writing a 1 to the bus keeps all the current devices and moves us to the next bit:<p></p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-Zd149KM8bUI/X_irDfyWeoI/AAAAAAAAk60/_o0yjxe-Ilscsi3Z3OJmyKAEoIzTZjzagCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-Zd149KM8bUI/X_irDfyWeoI/AAAAAAAAk60/_o0yjxe-Ilscsi3Z3OJmyKAEoIzTZjzagCLcBGAsYHQ/s16000/image.png" /></a></div><br />At this point the master knows that all remaining devices have a 0 in this position. It records the 0 and writes a 0 to the bus. Since device #2 has reached the end of its serial number, it takes itself out of the search in response to the write the master has performed (which would normally cause the device to get ready to send its next bit).<p></p><p style="text-align: left;">Now, with no devices left in the search, and due to the pull-up on the bus, when the master performs its next 2 reads it gets:</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-P94FdiEMKaA/X_ir7e17FCI/AAAAAAAAk7A/o5TZJdbvyzkhlCpw2neP4dTSL1CQEIT8QCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-P94FdiEMKaA/X_ir7e17FCI/AAAAAAAAk7A/o5TZJdbvyzkhlCpw2neP4dTSL1CQEIT8QCLcBGAsYHQ/s16000/image.png" /></a></div><br />When the master receives a 11 it knows that it has found the unique serial number of one of the devices attached to its bus: 01010000. We know this as the serial number of device #2.<p></p><p>Remember: the master is blind! <i>We</i> can see that there are 4 devices in total and that their serial numbers all consist of 8 bits, but the master doesn't know either of these things. However, the master is not dumb. It does know that of all the serial numbers present, none of them have 1 bits in either the 1st or 2nd positions. The master doesn't have to perform an exhaustive search of the entire bit-space to find all the devices, it only needs to follow-up with all of the forks it encounters each time through.</p><p style="text-align: left;">During the last pass the master encountered a fork; in fact it encountered 2 forks. Each time it found a fork it saved the state of the serial number up until that point, plus the "other path". I.e. at the 3rd bit position a fork was found, this indicated to the master that there were two valid paths at this point "000" and "100". We decided, arbitrarily, to follow the "000" path, so we saved the "100" path for later. The same thing happened at bit position 6. When examining the 6th bit position of the devices that were part of the search up until that point we found another 2 paths: "010000" and "110000". Now we need to go back to find what exists along the "100" and "110000" paths.</p><p style="text-align: left;">At this point the master sends a RESET to all devices and issues the ROM-search command. This puts all devices back into the search (including any ones we've already found) and gets all devices ready to send their 1st bits again.</p><p style="text-align: left;">However, the difference this time is that the master is not starting from scratch; it already knows that something exists along the "100" and "110000" paths and that no "1"s can possibly exist in bit positions 1 and 2.</p><p style="text-align: left;">We arbitrarily decide to investigate the "100" partial serial number. All devices are ready to send their first bits, so the master performs 2 reads. There's no need to process the result since we already know how it turns out, so the master can simply write a 0 to the bus (which is the value of the 1st bit in the partial serial number "100" that we are currently following). All devices that have a 0 in the 1st position get ready to send the next bit. The master performs 2 reads, ignores this result as well (since we're at the 2nd position of a known partial serial id "100"), and writes a 0 to the bus again. A third set of 2 reads is performed and the master ignores this value too.</p><p style="text-align: left;">This time, however, a different path is taken than before. Previously at the 3rd bit position we arbitrarily decided to take the "0" path and save the "1" path for later. We are now at "later". This time we're following up on the known partial serial number of "100", so this time we're going to write a 1 for the 3rd bit of the search pattern. When the master writes a 1 on the data bus, devices #1 and #4 will continue on as part of the search, and devices #2 and #3 will drop out.</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-woWMiDZFFAY/X_jI7J3wo3I/AAAAAAAAk7Y/jnksaHg0R44BI5gP9EsqKk2nZ-hpEU-twCLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="173" data-original-width="547" src="https://lh3.googleusercontent.com/-woWMiDZFFAY/X_jI7J3wo3I/AAAAAAAAk7Y/jnksaHg0R44BI5gP9EsqKk2nZ-hpEU-twCLcBGAsYHQ/s16000/image.png" /></a></div><br />The number of forks, so far, along <i>this</i> path is zero (although there is a fork to come).<p></p><p style="text-align: left;">Keeping track of all the forks that are found, and the partial serial numbers that go along with them, will lead to finding all the serial numbers of all the devices attached to the bus.</p><p>Notice that when the RESET and ROMsearch were issued most recently, device #2 became part of the search again. But we will never "find" device #2 again because we've already found it by arbitrarily following all the "0" paths the first time, and all subsequent passes through the algorithm will start with already-known partial serial IDs. Given that all serial numbers are assumed to be unique and of the same length, we won't ever "find" an already-found device again.</p><p>As a result, all devices are only found once, and alleys that don't lead to valid serial numbers are never explored.</p><h3 style="text-align: left;">Implementation Details</h3><p>As mentioned above, this algorithm is implemented as two programs which communicate over a pair of named fifos.</p><p>The testing program needs to be started first. It will create a pair of fifos. The ROMsearch program can then be started. It will use these fifos to communicate with the testing program. As the ROMsearch program performs reads and writes to the fifos the testing program will send back appropriate responses based on its list of devices.</p><p>Alternatively, you could interact with the testing program "by hand" by writing commands into the "toTesterFifoFd" fifo (echo -n R > toTesterFifoFd) and seeing what comes out the "fmTesterFifoFd" fifo (cat fmTesterFifoFd). In this way you could perform an interactive ROMsearch if you wished. All communication done through the fifos is done using ASCII characters.</p><p>Note that in the following example run, the replies coming back from the testing program in response to the reads being performed by the master (cat fmTesterFifoFd) are interspersed with the output of the testing program itself which is set to verbose mode. So you have to search a little to find the two zeros that the tester is sending back to the master when the master issues its two 'r' commands in the following sequence.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> ./tester &
<span style="color: #777777;">[1] 9808</span>
<span style="color: #777777;">devices: 7</span>
<span style="color: #777777;">bitsize: 8</span>
<span style="color: #777777;">devices_pG[00] = 170 (0b10101010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[01] = 040 (0b00101000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[02] = 115 (0b01110011) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[03] = 085 (0b01010101) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[04] = 162 (0b10100010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[05] = 224 (0b11100000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[06] = 024 (0b00011000) current bit pos:00 → 0</span>
<span style="color: #348c00;">$</span> ls
<span style="color: #777777;">Makefile ROMsearch.o common.o data02 data04 fmTesterFifoFd tester.o</span>
<span style="color: #777777;">ROMsearch baddata data01 data03 data05 tester toTesterFifoFd</span>
<span style="color: #348c00;">$</span> cat fmTesterFifoFd &
<span style="color: #777777;">[2] 9862</span>
<span style="color: #348c00;">$</span> echo -n V > toTesterFifoFd
<span style="color: #777777;">devices_pG[00] = 170 (0b10101010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[01] = 040 (0b00101000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[02] = 115 (0b01110011) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[03] = 085 (0b01010101) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[04] = 162 (0b10100010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[05] = 224 (0b11100000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[06] = 024 (0b00011000) current bit pos:00 → 0</span>
<span style="color: #348c00;">$</span> echo -n R > toTesterFifoFd
<span style="color: #777777;">fifo: 0x52 (R) cnt:1 bitPos:0</span>
<span style="color: #777777;">devices_pG[00] = 170 (0b10101010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[01] = 040 (0b00101000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[02] = 115 (0b01110011) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[03] = 085 (0b01010101) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[04] = 162 (0b10100010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[05] = 224 (0b11100000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[06] = 024 (0b00011000) current bit pos:00 → 0</span>
<span style="color: #348c00;">$</span> echo -n S > toTesterFifoFd
<span style="color: #777777;">fifo: 0x53 (S) cnt:1 bitPos:0</span>
<span style="color: #777777;">devices_pG[00] = 170 (0b10101010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[01] = 040 (0b00101000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[02] = 115 (0b01110011) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[03] = 085 (0b01010101) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[04] = 162 (0b10100010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[05] = 224 (0b11100000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[06] = 024 (0b00011000) current bit pos:00 → 0</span>
<span style="color: #348c00;">$</span> echo -n r > toTesterFifoFd
<span style="color: #777777;">fifo: 0x72 (r) cnt:1 bitPos:0</span>
<span style="color: #777777;"> readState:0 bitPos:0</span>
<span style="color: #777777;"> in search [00] bit:0</span>
<span style="color: #777777;"> in search [01] bit:0</span>
<span style="color: #777777;"> in search [02] bit:1</span>
<span style="color: #777777;"> in search [03] bit:1</span>
<span style="color: #777777;"> in search [04] bit:0</span>
<span style="color: #777777;"> in search [05] bit:0</span>
<span style="color: #777777;"> in search [06] bit:0</span>
<span style="color: #777777;"> <= 0</span>
<span style="color: #777777;">devices_pG[00] = 170 (0b10101010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[01] = 040 (0b00101000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[02] = 115 (0b01110011) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[03] = 085 (0b01010101) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[04] = 162 (0b10100010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[05] = 224 (0b11100000) current bit pos:00 → 0</span>
<span style="color: #777777;">0devices_pG[06] = 024 (0b00011000) current bit pos:00 → 0</span>
<span style="color: #348c00;">$</span> echo -n r > toTesterFifoFd
<span style="color: #777777;">fifo: 0x72 (r) cnt:1 bitPos:0</span>
<span style="color: #777777;"> readState:1 bitPos:0</span>
<span style="color: #777777;"> in search [00] ~bit:1</span>
<span style="color: #777777;"> in search [01] ~bit:1</span>
<span style="color: #777777;"> in search [02] ~bit:0</span>
<span style="color: #777777;"> in search [03] ~bit:0</span>
<span style="color: #777777;"> in search [04] ~bit:1</span>
<span style="color: #777777;"> in search [05] ~bit:1</span>
<span style="color: #777777;"> in search [06] ~bit:1</span>
<span style="color: #777777;"> <= 0</span>
<span style="color: #777777;">devices_pG[00] = 170 (0b10101010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[01] = 040 (0b00101000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[02] = 115 (0b01110011) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[03] = 085 (0b01010101) current bit pos:00 → 1</span>
<span style="color: #777777;">0devices_pG[04] = 162 (0b10100010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[05] = 224 (0b11100000) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[06] = 024 (0b00011000) current bit pos:00 → 0</span>
<span style="color: #348c00;">$</span> echo -n <span style="color: #3677a9;">0</span> > toTesterFifoFd
<span style="color: #777777;">fifo: 0x30 (0) cnt:1 bitPos:0</span>
<span style="color: #777777;"> readState:2 bitPos:0</span>
<span style="color: #777777;"> removing: 02</span>
<span style="color: #777777;"> removing: 03</span>
<span style="color: #777777;">devices_pG[00] = 170 (0b10101010) current bit pos:01 → 1</span>
<span style="color: #777777;">devices_pG[01] = 040 (0b00101000) current bit pos:01 → 0</span>
<span style="color: #777777;">devices_pG[04] = 162 (0b10100010) current bit pos:01 → 1</span>
<span style="color: #777777;">devices_pG[05] = 224 (0b11100000) current bit pos:01 → 0</span>
<span style="color: #777777;">devices_pG[06] = 024 (0b00011000) current bit pos:01 → 0</span>
</pre></div>
<p>The testing program takes an optional cmdline argument. This argument names a file whose contents are the data to be used. This data represents a list of unique serial numbers for the search program to find. The first line of the data file specifies the number of devices (N), the second line specifies the bit size of the devices, and the subsequent N lines start with a unique positive integer number representing the serial IDs of each of the devices connected to the 1-wire bus. If no file is specified, the test program will simply generate random data (time-seeded) to use.</p><p>When generating random data, you can tell the testing program the bit size to use via the -b/--bitsize cmdline option, and you can specify the maximum number of devices to generate using the -m/--max-devices cmdline argument. Note that by specifying the maximum number of devices this doesn't mean that this many devices will be created; a random number of devices will be created, up to a maximum of the number given.</p><p>Note: the program has provisions to make sure that the max-devices and bitsize options make sense. You can't set the bitsize to 4, then ask for a maximum of 1000 devices.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> ./tester -b4 -m1000
<span style="color: #777777;">the given bit size (4) is not high enough to randomly</span>
<span style="color: #777777;">generate the requested number of max entries (1000)</span>
<span style="color: #777777;">please either increase the bit size</span>
<span style="color: #777777;">or reduce the number of max entries to 7 or less</span>
</pre></div>
<p>The help for the testing program is as follows:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> ./tester -h
<span style="color: #777777;">ROMsearch 1.0.0</span>
<span style="color: #777777;">usage: ./tester [<options>] [<testfile>]</span>
<span style="color: #777777;"> where:</span>
<span style="color: #777777;"> <testfile> a file from which to get serial ID data</span>
<span style="color: #777777;"> (otherwise the data is generated randomly)</span>
<span style="color: #777777;"> <options></span>
<span style="color: #777777;"> -h|--help print information about this program and exit successfully</span>
<span style="color: #777777;"> -b|--bitsize <b> set the number of bits in the serial ID to <b> (MIN:2 default:8 MAX:64)</span>
<span style="color: #777777;"> -m|--max-devices <m> set the maximum number of devices (MIN:1 default:8)</span>
</pre></div>
<p>Note that if you specify a testfile to use and try to specify a max-devices and/or bitsize, the max-devices and/or bitsize options will be ignored:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> ./tester -b8 -m20 data01
<span style="color: #777777;">WARNING: specifying the bit size and/or max entries on the cmdline</span>
<span style="color: #777777;"> is not compatible with using pre-generated data from a file</span>
<span style="color: #777777;">these cmdline options will be ignored in favour of the values from the datafile</span>
<span style="color: #777777;">devices: 3</span>
<span style="color: #777777;">bitsize: 8</span>
<span style="color: #777777;">devices_pG[00] = 210 (0b11010010) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[01] = 205 (0b11001101) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[02] = 164 (0b10100100) current bit pos:00 → 0</span>
</pre></div>
<p>The testing program understands the following commands on the "toTesterFifoFd" fifo:</p><p></p><ul style="text-align: left;"><li>r</li><ul><li>The master is performing a read on the bus. The tester writes the logical AND of all the current bits of each of the device's serial numbers that are still part of the search as one value. If this is the second such 'r' command then the tester will AND the complement of all the device's current serial bits of the devices that are still part of the search.</li></ul><li>R</li><ul><li>RESET. The tester resets the current bit position back to the beginning (i.e. bit 0, LSb first) and resets the state back to expecting the ROM command (i.e. ROMsearch).</li></ul><li>S</li><ul><li>ROMsearch. After coming out of RESET, the devices need to know which function to perform. Currently the only supported function is ROMsearch, but I include it in order to be faithful to the 1-wire protocol.</li></ul><li>0 or 1</li><ul><li>The master is choosing which devices are to continue on being part of the search, and which are go to idle until the next RESET. Any device whose current serial ID bit position contains either the '0' or the '1' that is sent by the master remain in the search.</li></ul><li>Q</li><ul><li>I've added this command so the master can tell the testing program that it is done, so the tester can terminate gracefully.</li></ul><li>V</li><ul><li>Another command I added to toggle the verbosity of the tester.</li></ul></ul><p></p><p style="text-align: left;">The ROMsearch program takes no arguments; it simply looks for the "toTesterFifoFd" and "fmTesterFifoFd" fifos and begins running through the ROMsearch algorithm to find all the devices represented in the testing program. As it finds devices, it prints their serial IDs to stdout.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> ./tester &
<span style="color: #777777;">[1] 11651</span>
<span style="color: #777777;">devices: 5</span>
<span style="color: #777777;">bitsize: 8</span>
<span style="color: #777777;">devices_pG[00] = 060 (0b00111100) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[01] = 188 (0b10111100) current bit pos:00 → 0</span>
<span style="color: #777777;">devices_pG[02] = 007 (0b00000111) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[03] = 061 (0b00111101) current bit pos:00 → 1</span>
<span style="color: #777777;">devices_pG[04] = 197 (0b11000101) current bit pos:00 → 1</span>
<span style="color: #348c00;">$</span> ./ROMsearch
<span style="color: #777777;">00011110...060</span>
<span style="color: #777777;">01100010...197</span>
<span style="color: #777777;">01011110...188</span>
<span style="color: #777777;">00000011...007</span>
<span style="color: #777777;">00011110...061</span>
<span style="color: #777777;">[1]+ Done ./tester</span>
</pre></div>
</div>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-20254560828638443682020-12-30T00:42:00.003-05:002022-03-21T08:44:51.081-04:00Multiple DS18B20 Temperature Probes<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-S6JekDsqhK8/X-wI9MKBdXI/AAAAAAAAkj4/Yb3D5oGIEBA4YQ5dzr8vdENsmdM3J_RRwCLcBGAsYHQ/s563/IMG_100EOS7D_4328.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="504" data-original-width="563" src="https://1.bp.blogspot.com/-S6JekDsqhK8/X-wI9MKBdXI/AAAAAAAAkj4/Yb3D5oGIEBA4YQ5dzr8vdENsmdM3J_RRwCLcBGAsYHQ/s16000/IMG_100EOS7D_4328.JPG" /></a></div><br /><p>In my <a href="https://twoerner.blogspot.com/2020/12/temperature-readings-with-ds18b20-and.html" target="_blank">last post</a> I hooked up <i>one</i> DS18B20 to a RaspberryPi. The neat thing about the DS18B20 and the 1-wire protocol is that multiple such devices can be connected together in a star topology. What's really great about this is that identifying an individual sensor doesn't depend on its position in a chain (for example) each device has its own unique 64-bit identifier. This means the layout of the probes doesn't have to be determined ahead of time. Also the length of the wires attached to the sensor can vary by a considerable amount. Therefore sensors near and far can be connected to the same microcontroller.</p><p>I had a number of varieties of protoboard, one of which is this type which features long buses:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-U035dD1_0yY/X-uwT1vYXBI/AAAAAAAAkik/YTbQP_Cj-2YM9i6H_KCwe2abjXcPAnCbwCLcBGAsYHQ/s600/protoboard.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="395" src="https://1.bp.blogspot.com/-U035dD1_0yY/X-uwT1vYXBI/AAAAAAAAkik/YTbQP_Cj-2YM9i6H_KCwe2abjXcPAnCbwCLcBGAsYHQ/s16000/protoboard.JPG" /></a></div><br /><p>This style of board works perfectly for this scenario.</p><p>I also happened to have a bunch of these x3 male headers. Most likely from some servo project.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-2xFFqU9rSvw/X-vz6ssV2bI/AAAAAAAAki8/uc1KY4zAxCwj9NhAi3sFusdhXt94YlXYwCLcBGAsYHQ/s266/IMG_100EOS7D_4322.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="189" data-original-width="266" src="https://1.bp.blogspot.com/-2xFFqU9rSvw/X-vz6ssV2bI/AAAAAAAAki8/uc1KY4zAxCwj9NhAi3sFusdhXt94YlXYwCLcBGAsYHQ/s16000/IMG_100EOS7D_4322.JPG" /></a></div><br /><p>Wouldn't it be great if there were a way to add a connector to the end of the temperature probes so they could plug into this header easily? As it turns out, it's <a href="https://www.pololu.com/" target="_blank">Pololu</a> to the rescue! Among the many things they sell, they also have <a href="https://www.pololu.com/category/70/crimp-connector-housings" target="_blank">crimp connector housings</a> in various configurations, and all the <a href="https://www.pololu.com/product/1931" target="_blank">other</a> <a href="https://www.pololu.com/product/1930" target="_blank">accessories</a> <a href="https://www.pololu.com/product/1928" target="_blank">to go with it</a>.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-anDiQ4BXnDg/X-wCnrXIXuI/AAAAAAAAkjM/aBNbBh7Atlsb3ntAtkRv0I5FT7_HnxhuACLcBGAsYHQ/s692/IMG_100EOS7D_4319.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="692" src="https://1.bp.blogspot.com/-anDiQ4BXnDg/X-wCnrXIXuI/AAAAAAAAkjM/aBNbBh7Atlsb3ntAtkRv0I5FT7_HnxhuACLcBGAsYHQ/s16000/IMG_100EOS7D_4319.JPG" /></a></div><br /><p>I know this probably sounds like I have some relationship with Pololu but I don't. I know other electronics suppliers provide such items too, but Pololu's site makes it quite easy to buy the right things the first time around <i>and</i> give me the confidence to try this out (thanks to their supporting videos and information). After a little practice on test wires I'm able to add connectors to my temperature probes:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-fYFrEn8ozq0/X-wCchjRWcI/AAAAAAAAkjI/TBYlDzwa9sw22C3fPo65Pgu2lWEfUzbcQCLcBGAsYHQ/s600/IMG_100EOS7D_4320.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="530" src="https://1.bp.blogspot.com/-fYFrEn8ozq0/X-wCchjRWcI/AAAAAAAAkjI/TBYlDzwa9sw22C3fPo65Pgu2lWEfUzbcQCLcBGAsYHQ/s16000/IMG_100EOS7D_4320.JPG" /></a></div><br /><p>Cutting off a piece of protoboard and soldering on the header gives me a hub into which to plug all the temperature probes. Since we need a 4.7k pull-up resistor in the design anyway, I might as well add it to the hub so it's ready to go:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-iVvDO__r77w/X-wGpPcEWiI/AAAAAAAAkjc/AmPVHzQlbvMvY0LZBBoMZ0dX7AzUIoTdQCLcBGAsYHQ/s400/IMG_100EOS7D_4323.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="214" data-original-width="400" src="https://1.bp.blogspot.com/-iVvDO__r77w/X-wGpPcEWiI/AAAAAAAAkjc/AmPVHzQlbvMvY0LZBBoMZ0dX7AzUIoTdQCLcBGAsYHQ/s16000/IMG_100EOS7D_4323.JPG" /></a></div><br /><p>You'll notice there's no picture of the underside 😉 It's bad enough showing this hack job from the top, I'm not about to show the disaster on the other side. Thankfully all the buses are still separate from each other, and that's all that matters 😂</p><p>With the pull-up resistor in place I'm forcing the middle bus to be the ground. The connectors aren't keyed, so I just have to line up the V<sub>DD</sub> and DQ lines together myself.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-qpuaWlprv2I/X-wH6M6J5BI/AAAAAAAAkjo/fufYbJs2XhYrBgP7JuqgmBjysvi7PPmFwCLcBGAsYHQ/s591/IMG_100EOS7D_4326.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="447" data-original-width="591" src="https://1.bp.blogspot.com/-qpuaWlprv2I/X-wH6M6J5BI/AAAAAAAAkjo/fufYbJs2XhYrBgP7JuqgmBjysvi7PPmFwCLcBGAsYHQ/s16000/IMG_100EOS7D_4326.JPG" /></a></div><br /><p>…and with the RaspberryPi:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-UkJSoHjASt4/X-wICBRWP8I/AAAAAAAAkjs/dd0sRL9N_wclf-dxC__Xrb0l-6Qq5zOrACLcBGAsYHQ/s800/IMG_100EOS7D_4333.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="533" data-original-width="800" src="https://1.bp.blogspot.com/-UkJSoHjASt4/X-wICBRWP8I/AAAAAAAAkjs/dd0sRL9N_wclf-dxC__Xrb0l-6Qq5zOrACLcBGAsYHQ/s16000/IMG_100EOS7D_4333.JPG" /></a></div><br /><p>Now when I boot my device I get a kernel log message about my GPIO setup and one log message each for each of the sensors attached to my hub:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">[ 5.135283] gpio-25 (onewire@19): enforced open drain please flag it properly in DT/ACPI DSDT/board file</span>
<span style="color: #777777;">[ 5.202823] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131bb70fee crc 30</span>
<span style="color: #777777;">[ 5.497062] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b7ad963 crc f6</span>
<span style="color: #777777;">[ 5.599175] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b62790b crc 83</span>
</pre></div>
<p>Note: these messages don't appear side-by-side in the log, but they do appear in this order.</p><p>Now when I look in the 1-wire sysfs location I find:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@raspberrypi3-64:~#</span> cd /sys/bus/w1/devices/
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> ls -l
<span style="color: #777777;">lrwxrwxrwx 1 root root 0 Dec 29 04:22 28-01131b62790b -> ../../../devices/w1_bus_master1/28-01131b62790b</span>
<span style="color: #777777;">lrwxrwxrwx 1 root root 0 Dec 29 04:22 28-01131b7ad963 -> ../../../devices/w1_bus_master1/28-01131b7ad963</span>
<span style="color: #777777;">lrwxrwxrwx 1 root root 0 Dec 29 04:22 28-01131bb70fee -> ../../../devices/w1_bus_master1/28-01131bb70fee</span>
<span style="color: #777777;">lrwxrwxrwx 1 root root 0 Dec 29 04:22 w1_bus_master1 -> ../../../devices/w1_bus_master1</span>
</pre></div>
<p>To read the temperatures of the probes I could visit each probe individually and simply "cat" the "temperature" file. This will cause the kernel to perform the "Convert T [44h]" command followed by the "Read Scratchpad [BEh]" command on each probe individually.</p><p>A small performance improvement can be had by visiting the master driver device and issuing a "trigger" command to its "therm_bulk_read" sysfs entry, then reading the temperatures from the probe devices individually. This causes the "Convert T [44h]" command to be issued to all the temperature probes connected to this master.</p><p>Notice that once the bulk command is given, the value of "therm_bulk_read" will read -1 if at least one sensor is still performing the conversion, 1 if one of the sensors has not had its temperature read out, and 0 once all the temperatures have been read for the most recent bulk conversion:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@raspberrypi3-64:~#</span> cd /sys/bus/w1/devices/
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> ls -1
<span style="color: #777777;">28-01131b62790b</span>
<span style="color: #777777;">28-01131b7ad963</span>
<span style="color: #777777;">28-01131bb70fee</span>
<span style="color: #777777;">w1_bus_master1</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> cat w1_bus_master1/therm_bulk_read
<span style="color: #777777;">0</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> echo <span style="color: #bf7f0f;">"trigger"</span> > w1_bus_master1/therm_bulk_read
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> cat w1_bus_master1/therm_bulk_read
<span style="color: #777777;">1</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> cat <span style="color: #3677a9;">28</span>-01131b62790b/temperature
<span style="color: #777777;">23375</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> cat w1_bus_master1/therm_bulk_read
<span style="color: #777777;">1</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> cat <span style="color: #3677a9;">28</span>-01131b7ad963/temperature <span style="color: #3677a9;">28</span>-01131bb70fee/temperature
<span style="color: #777777;">23125</span>
<span style="color: #777777;">23437</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> cat w1_bus_master1/therm_bulk_read
<span style="color: #777777;">0</span>
</pre></div>
<p>Note that I can't issue the bulk command and read out the status fast enough to demonstrate the -1 case. Writing the "trigger" to start the bulk command appears to block until all the probes have performed their temperature conversions.</p><p>The interesting thing about the bulk command is that it allows all the probes to check their temperatures at roughly the same time, then the code can take its time reading out the temperatures that existed when the bulk command was given. If each probe were to be visited one at a time, the timing of the temperature checks from all the probes would be skewed. This might not be a problem, but it's handy having this feature available.</p><p>Another neat thing about this setup is that the kernel actively probes the 1-wire bus during its operation. Therefore adding probes is plug-and-play at runtime! If a new probe is added to the bus at runtime, the kernel detects it, adds it to the list of devices, and prints a message indicating the probe's unique serial number. This feature makes it easier to add probes to an installation and correlate which probe is measuring which temperature. For example, if you have a project that needs 5 probes, each probe measuring a different part of a project, you can boot your hardware with the probes un-attached then attach them one-by-one to the bus at runtime taking note of their serial numbers and the part of the project each probe is measuring as they're being added.</p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-69770723811860221722020-12-29T11:00:00.036-05:002022-03-21T08:44:45.748-04:00Temperature Readings with the DS18B20 and OpenEmbedded/Yocto<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-bgnxVtKCoys/X-pYJuhgMNI/AAAAAAAAkgU/_mZHAINWhQ8W3KhwpY9vu10143sFnBo5gCLcBGAsYHQ/s800/IMG_100EOS7D_4312.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="533" data-original-width="800" src="https://1.bp.blogspot.com/-bgnxVtKCoys/X-pYJuhgMNI/AAAAAAAAkgU/_mZHAINWhQ8W3KhwpY9vu10143sFnBo5gCLcBGAsYHQ/s16000/IMG_100EOS7D_4312.JPG" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p>There are many ways to read a temperature in an electronics project. Probably the easiest way under Linux is with one of those pre-wired waterproof <a href="https://www.dfrobot.com/product-689.html" target="_blank">DS18B20</a> devices. Wire-up the probe to your RaspberryPi, enable a device-tree overlay, and read a file.</p><h3 style="text-align: left;">Wiring</h3><p>The <a href="https://image.dfrobot.com/image/data/DFR0198/DS18B20.pdf" target="_blank">datasheet</a> for the DS18B20 has all the information you'll need (and more). The probe has 3 wires: ground (black), DQ data in/out (yellow), and V<sub>DD</sub> (red). Technically the device doesn't actually need V<sub>DD</sub> connected, it can siphon enough parasitic power from DQ in normal operation. But since there's already a RaspberryPi in the design, it provides a convenient 5V, and connecting V<sub>DD</sub> makes the conversion potentially faster and more stable... might as well use it.</p><p>The datasheet recommends using a 4.7k pull-up on the DQ line. Grabbing 5V and ground from the RaspberryPi, I've wired up the probe as follows:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/--tUR2h9eUHg/X-pdMwAS8xI/AAAAAAAAkgo/CUHPmdo0hKkFr7mTTkXCVopT4HCDMK7-wCLcBGAsYHQ/s336/IMG_100EOS7D_4305.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="336" data-original-width="250" src="https://1.bp.blogspot.com/--tUR2h9eUHg/X-pdMwAS8xI/AAAAAAAAkgo/CUHPmdo0hKkFr7mTTkXCVopT4HCDMK7-wCLcBGAsYHQ/s16000/IMG_100EOS7D_4305.JPG" /></a></div><br /><p>The 3-wire bundle comes from the probe, the individual wires run back to the RaspberryPi:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-pxYvb6BH3UY/X-pehvMfu3I/AAAAAAAAkg0/rX-EDrw8YH8Lahm0EERkm0U_KEW2yHF3ACLcBGAsYHQ/s359/IMG_100EOS7D_4318.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="359" data-original-width="205" src="https://1.bp.blogspot.com/-pxYvb6BH3UY/X-pehvMfu3I/AAAAAAAAkg0/rX-EDrw8YH8Lahm0EERkm0U_KEW2yHF3ACLcBGAsYHQ/s16000/IMG_100EOS7D_4318.JPG" /></a></div><br /><p>Connected to the RaspberryPi, the 3-wire bundle is my console cable, the individual wires run to the protoboard. The black wire is on ground, the red wire is on +5V. In my case I've decided to use the RaspberryPi's GPIO04, therefore the yellow wire is connected to pin07.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-2QWzqBaYqPg/X-puMl-3tsI/AAAAAAAAkhE/9s5s0CpgFpkjxuM3INf8B4YCc-qp6j6ZACLcBGAsYHQ/s419/IMG_100EOS7D_4310.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="419" data-original-width="312" src="https://1.bp.blogspot.com/-2QWzqBaYqPg/X-puMl-3tsI/AAAAAAAAkhE/9s5s0CpgFpkjxuM3INf8B4YCc-qp6j6ZACLcBGAsYHQ/s16000/IMG_100EOS7D_4310.JPG" /></a></div><br /><p><br /></p><h3 style="text-align: left;">Build</h3><p style="text-align: left;">By default the meta-raspberrypi OE/Yocto BSP layer uses the <a href="https://github.com/raspberrypi/linux" target="_blank">out-of-tree raspberrypi kernel</a>. One of the differences between it and upstream is that the out-of-tree raspberrypi kernel contains all the device-tree overlays specific to the RaspberryPi. To interface with the DS18B20 the 1-wire overlay needs to be enabled in the RaspberryPi's config.txt. In OpenEmbedded/Yocto we use the RPI_EXTRA_CONFIG variable to enable arbitrary configurations in config.txt.</p><p style="text-align: left;">In addition to enabling the 1-wire protocol, we also need to specify the GPIO pin on which we want it to operate. In my specific case, given how I've wired the circuit, I'm using GPIO04, therefore I relay that information as follows:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">RPI_EXTRA_CONFIG</span> = <span style="color: #bf7f0f;">"\</span>
<span style="color: #777777; font-style: italic;"># enable 1-wire on gpio 4 \n\</span>
<span style="color: #bf7f0f;">dtoverlay=w1-gpio,gpiopin=4"</span>
</pre></div>
<p style="text-align: left;">If you're building a core-image-minimal, you'll probably also want to add the following to your build:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">CORE_IMAGE_EXTRA_INSTALL</span> += <span style="color: #bf7f0f;">" \</span>
<span style="color: #bf7f0f;"> </span><span style="color: #777777; font-style: italic;">${MACHINE_EXTRA_RRECOMMENDS}</span><span style="color: #bf7f0f;"> \</span>
<span style="color: #bf7f0f;"> "</span>
</pre></div>
<p style="text-align: left;">Building, flashing, and running the image from OpenEmbedded/Yocto you should see something along the following flash by on the serial console as it boots:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">[ 5.047539] gpio-4 (onewire@4): enforced open drain please flag it properly in DT/ACPI DSDT/board file</span>
<span style="color: #777777;">[ 5.090044] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b62790b crc 83</span>
</pre></div>
<p style="text-align: left;">This is good, it means everything is configured properly and the kernel has noticed the temperature probe connected to GPIO04 via 1-wire.</p><p style="text-align: left;">Note that in the case of the DS18B20, each device has a unique 64-bit serial number. So your output should be similar but will be slightly different. The "28" identifies this specific 1-wire device (i.e. the DS18B20), the hex value following the decimal point is the 48-bit unique serial number of my specific device. The last byte is a CRC of the first 56 bits.</p><h3 style="text-align: left;">Read A File</h3><p style="text-align: left;">If everything is working properly and you've seen the previous messages in your system log as the device boots then everything should be set. Any devices that are detected can be found under /sys/bus/w1:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@raspberrypi3-64:~#</span> cd /sys/bus/w1
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1#</span> ls
<span style="color: #777777;">devices drivers drivers_autoprobe drivers_probe uevent</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1#</span> cd devices/
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> ls
<span style="color: #777777;">28-01131b62790b w1_bus_master1</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/bus/w1/devices#</span> cd <span style="color: #3677a9;">28</span>-01131b62790b/
<span style="color: #348c00;">root@raspberrypi3-64:/sys/devices/w1_bus_master1/28-01131b62790b#</span> ls -l
<span style="color: #777777;">-rw-r--r-- 1 root root 4096 Dec 29 05:35 alarms</span>
<span style="color: #777777;">lrwxrwxrwx 1 root root 0 Dec 29 05:35 driver -> ../../../bus/w1/drivers/w1_slave_drive</span>
<span style="color: #777777;">r</span>
<span style="color: #777777;">--w------- 1 root root 4096 Dec 29 05:35 eeprom</span>
<span style="color: #777777;">-r--r--r-- 1 root root 4096 Dec 29 05:35 ext_power</span>
<span style="color: #777777;">drwxr-xr-x 3 root root 0 Dec 29 04:26 hwmon</span>
<span style="color: #777777;">-r--r--r-- 1 root root 4096 Dec 29 05:35 id</span>
<span style="color: #777777;">-r--r--r-- 1 root root 4096 Dec 29 05:35 name</span>
<span style="color: #777777;">drwxr-xr-x 2 root root 0 Dec 29 05:35 power</span>
<span style="color: #777777;">-rw-r--r-- 1 root root 4096 Dec 29 05:35 resolution</span>
<span style="color: #777777;">lrwxrwxrwx 1 root root 0 Dec 29 05:35 subsystem -> ../../../bus/w1</span>
<span style="color: #777777;">-r--r--r-- 1 root root 4096 Dec 29 04:28 temperature</span>
<span style="color: #777777;">-rw-r--r-- 1 root root 4096 Dec 29 04:26 uevent</span>
<span style="color: #777777;">-rw-r--r-- 1 root root 4096 Dec 29 05:35 w1_slave</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/devices/w1_bus_master1/28-01131b62790b#</span> cat temperature
<span style="color: #777777;">23625</span>
<span style="color: #348c00;">root@raspberrypi3-64:/sys/devices/w1_bus_master1/28-01131b62790b#</span> hexdump -C id
<span style="color: #777777;">00000000 28 0b 79 62 1b 13 01 83 |(.yb....|</span>
<span style="color: #777777;">00000008</span>
</pre></div>
<p style="text-align: left;">As you can see, the temperature probe is automatically detected, and Linux handles all the details. Simply reading the "temperature" sysfs entry causes the kernel to ask the device to perform a temperature reading, then fetch the value from the device. Under the hood a lot of details are being handled by the kernel. Note, the reported temperature at this point is 23.625°C.</p><h3 style="text-align: left;">Notes</h3><p style="text-align: left;">If I wanted to switch to, say, GPIO25 instead of GPIO04, all that would be required is to change where the yellow wire connects to the RaspberryPi's 40-pin header (switch from pin07 to pin22) and modify RPI_EXTRA_CONFIG as follows:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">RPI_EXTRA_CONFIG</span> = <span style="color: #bf7f0f;">"\</span>
<span style="color: #777777; font-style: italic;"># enable onewire on gpio 25 \n\</span>
<span style="color: #bf7f0f;">dtoverlay=w1-gpio,gpiopin=25"</span>
</pre></div>
<p style="text-align: left;">Build, update the µSD card, apply power… Now when I boot I get:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">[ 5.113801] gpio-25 (onewire@19): enforced open drain please flag it properly in DT/ACPI DSDT/board fi</span><span style="color: #777777;">le</span>
<span style="color: #777777;">[ 5.473042] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b62790b crc 83</span>
</pre></div>
<p style="text-align: left;">And everything continues to work as before:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@raspberrypi3-64:~#</span> cat /sys/bus/w1/devices/28-01131b62790b/temperature
<span style="color: #777777;">23500</span></pre></div>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-80113216324580195352020-12-27T10:35:00.002-05:002022-03-21T08:44:39.919-04:00psplash Improvements for OpenEmbedded/Yocto<p style="text-align: left;">The <a href="http://git.yoctoproject.org/cgit/cgit.cgi/psplash/" target="_blank">psplash project</a> uses fbdev graphics to show a logo on a screen during bootup and shutdown. It was started in 2006 and is meant for embedded systems. It is integrated into OpenEmbedded/Yocto quite well; simply add "splash" [NOTE: not "psplash"] to IMAGE_FEATURES and you're on your way.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">IMAGE_FEATURES</span> += <span style="color: #bf7f0f;">"splash"</span>
</pre></div>
<p style="text-align: left;">Of course there are caveats. For example the psplash program is run by the init system. On most embedded systems this means that it only runs after the bootloader, and only once the kernel gets to the point of starting userspace. Another caveat is that your kernel config needs to include (y) the appropriate fbdev driver into the kernel (and not as a module) otherwise by the time the module is loaded, psplash will be done its work.</p><p style="text-align: left;">By default, an oecore build will have an OpenEmbedded logo; a poky build uses a Yocto Project logo. Layers are free to override the image with whatever logo they want. meta-raspberrypi <a href="https://github.com/agherzan/meta-raspberrypi/tree/master/recipes-core/psplash" target="_blank">provides</a> a good example of this.</p><p style="text-align: left;">While I was playing around with psplash the other day, I noticed something peculiar. With qemu images everything works fine, if the init system is systemd everything is fine again. But on my raspberrypi build with sysvinit as the init system, psplash would fail to run on the very first boot. For the first shutdown, and every bootup and shutdown thereafter it works just fine. So why not on the first boot? Note also that currently sysvinit is still the default init system of an OE/Yocto build.</p><p style="text-align: left;">On a real system with real hardware, on the very first boot the filesystem is initially mounted read-only. Only later is the filesystem remounted read-write (and is forevermore read-write). One of the functions of the psplash program is to display a progress bar to give users a vague idea of the progress of the bootup. In order to communicate the progress to the psplash program, when it starts up the psplash program attempts to use, or create if it doesn't exist, a fifo. Processes that want to update the progress send text messages to the psplash program over its fifo.</p><p style="text-align: left;">Due to the fact that the psplash program is one of the very first things started by the init system, at the point where psplash is started on the very first boot, the filesystem is still mounted read-only. The psplash program would try to use a fifo if one existed, but prior to my investigation it isn't easy to place a fifo into a image that is being created. Since there is no pre-existing fifo the psplash program tries to create one. Since the filesystem is currently read-only, it fails at doing so and the psplash program terminates with error.</p><p style="text-align: left;">At some point in the first bootup the filesystem is re-mounted read-write, so all subsequent shutdowns and boots succeed at running psplash.</p><p style="text-align: left;">One of the unfortunate things about missing out on the first boot's psplash is due to the fact that the first boot of most images can often take longer than subsequent boots. Often times an image needs to do some housekeeping chores on the very first boot, but not on any others. For example: unique keys might need to be generated, post-install scripts might need to be run, etc. So having psplash work for all boots is a worthy goal.</p><p style="text-align: left;">My first thought was to get psplash to create its fifo in a part of the filesystem that is read-write from the start. It turns out that the root of the filesystem (i.e. /) is read-write from the start. Reviewers of that patch, however, weren't keen on the idea of messing up the root of the filesystem.</p><p style="text-align: left;">My next approach was to consider what would be involved in trying to add a fifo to an image that is being created. On the one hand, it's not hard at all: simply DEPEND on coreutils-native and call mkfifo to create the fifo in the staging area. In practice, however, I ran into a snag. The build ends up hanging forever until you kill it explicitly.</p><p style="text-align: left;">Turns out, when you perform a build with OpenEmbedded/Yocto, one of the great benefits is that the build includes a number of post-build steps that are run to check over various parts of the system for sanity. These checks and their logic are part of the insane.bbclass. As it turns out, one such check is to look for a shebang in the first line of all the files included in the image. The point of this check is to make sure that anything that is being shebanged (e.g. sh, bash, perl, python) is included in the runtime on-target image. Therefore the first line of every object in the image is checked. Unfortunately if the object happens to be a fifo, reading from it will hang forever waiting for data to appear.</p><p style="text-align: left;">Looking through the code of that bbclass, it wasn't all that hard to find the one and only case where a sanity check reads through the contents of all files. Adding an extra check to make sure that any object whose contents will be examined is not a fifo is all that was required.</p><p style="text-align: left;">Now that it was possible to create an image with an already-existing fifo, it was a simple matter of updating a recipe's install process to add a fifo to the image and point psplash to it.</p><p style="text-align: left;">Turns out others have noticed that adding fifos to an image isn't easily possible, so a bug was filed. Thankfully Richard Purdie remembered seeing the bug and made me aware that in my quest to get psplash working better, I was also helping to close a bug for the project! (yeah!!) Randy MacLeod had suggested that, as part of fixing the bug, an automated unit test should be added to make sure we don't accidentally lose the ability to add fifos to an image. A little bit of back-and-forth with Richard over IRC pointed me in the right direction of how to run the existing tests, and where to look to add a new fifo test.</p><p style="text-align: left;">While I was working on this project I had the opportunity to look through the psplash code itself. One thing I noticed is that in addition to sending messages via the fifo to update the progress, there is another message that can be sent to specify a text string to print immediately above the progress bar. Turns out there's an invisible text field just above the progress bar one can use to show messages to the user. I thought it would be a good addition to have the name of the current boot script displayed above the progress bar. In this way a user can see exactly what is running.</p><p style="text-align: left;">When a system is booting, the progress bar doesn't proceed smoothly; instead it updates in spurts and jumps. Sometimes the progress bar seemingly stops for a noticeable period of time. Showing the user what's currently running lets them know the reason for any pauses and provides for, in my opinion, a better user experience. Therefore, as part of my updates, I also added the plumbing necessary for the sysvinit system to provide not only a progress bar indication of the progress, but also a textual description of which startup/shutdown script is currently running.</p><p style="text-align: left;">Since, up until this point, showing a textual description of the progress hadn't been used, the feedback I was provided suggested that this new feature be added with a knob to turn it on and off, and that it should be off by default. Therefore should you want to enable it in your builds you'll need to:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">PACKAGECONFIG_pn-sysvinit</span> = <span style="color: #bf7f0f;">"psplash-text-updates"</span>
</pre></div>
<p style="text-align: left;"><br /></p><p style="text-align: left;">I've tried to capture the changes in the following video. Unfortunately the camera struggles to focus, so it's not the best video you'll see. Hopefully it conveys the gist.</p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxFc5bnQo95_AfufJzf6BF8eBHRhrTZeSIsRa6o6PAgZXiUMTpkvknK7BCeKrCKPqSQpTsUJc2X4TXl5P9T4A' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div><br /><p style="text-align: left;">The video shows the very first boot of a rasberrypi system. After the system finishes booting up, I then reboot the device. Notice how the sshd module takes a noticeable amount of time to run on the first boot, but is finished almost instantly the second time around.</p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com1tag:blogger.com,1999:blog-3897401118500109418.post-83966764278691229072020-12-17T01:07:00.004-05:002022-03-21T08:44:32.355-04:00Graphics with OpenEmbedded/Yocto without X11/Weston<p>In a <a href="https://twoerner.blogspot.com/2020/12/userland-graphics-with-openembeddedyocto.html" target="_blank">previous post</a> I discussed graphics on the RaspberryPi and how one could use the closed binary blob + the userland library to do GLESv2 without a windowing system/compositor. This solution resulted in a system image that only required 36 packages and is 28MB in size. However, this solution is RaspberryPi-specific, 32-bit-specific, GLESv2-specific, and the quality of the binary blob graphics lags noticeably behind the quality of the fully open-source alternatives.</p><p>A better, and more generic, solution is to use DRM/KMS, GBM, and EGL directly. This allows fullscreen, "bare-metal" playback of OpenGL or OpenGL ES apps without the weight of x11 or weston/wayland.</p><p>Examples of this usage can be found with: kmscube, glmark2, mpv, and kodi. mpv and kodi are huge applications with dozens of dependencies each, so they aren't good to use for this example where I'm trying to show how small a bare-metal graphics system can be.</p><p>In this case I'm going to demonstrate on the RaspberryPi, but this solution is generic enough to work with any board whose SoC has a GPU that is supported by Mesa's DRM. I'm using the following layers:</p><p></p><ul style="text-align: left;"><li>bitbake: 71aaac9efa69abbf6c27d174e0862644cbf674ef</li><li>openembedded-core: c58fcc1379ca5755a5b670f79b75e94370d4943c</li><li>meta-openembedded: f03ad4971ed0b7cf34550a90ee3c0fa18f964533</li><li>meta-raspberrypi: 361f42e346e59f3a3fafcfa4ab7c948969d5abf4</li></ul><p></p><p>The edits I've made to my conf/local.conf are:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5
6
7
8</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">MACHINE</span> = <span style="color: #bf7f0f;">"raspberrypi3-64"</span>
<span style="color: #2db5b5;">MACHINE_FEATURES_append</span> = <span style="color: #bf7f0f;">" vc4graphics"</span>
<span style="color: #2db5b5;">DISTRO_FEATURES</span> += <span style="color: #bf7f0f;">"opengl"</span>
<span style="color: #2db5b5;">CORE_IMAGE_EXTRA_INSTALL</span> += <span style="color: #bf7f0f;">"glmark2 kmscube"</span>
<span style="color: #2db5b5;">PACKAGECONFIG_append_pn-glmark2</span> = <span style="color: #bf7f0f;">" drm-gl"</span>
<span style="color: #2db5b5;">ENABLE_UART</span> = <span style="color: #bf7f0f;">"1"</span>
</pre></td></tr></tbody></table></div>
<p>Note:</p><p></p><ul style="text-align: left;"><li>I'm using "raspberrypi3-64" as my MACHINE, the same works for "raspberrypi3" (i.e. a 32-bit build) as well as a whole bunch of other devices/machines</li><li>on line 3 I'm specifically requesting the fully open-source graphics stack based on Mesa</li><li>notice that I'm only adding "opengl" to the DISTRO_FEATURES, and not "x11" (or "wayland")</li><li>on line 5 I want glmark2 and kmscube added to my image</li><li>by default, the way the glmark2 recipe is written, it will build drm-gles2 by default, to get drm-gl built as well I've added it to its PACKAGECONFIG</li><li>I like enabling the UART and using the board via the serial console</li></ul><p></p><p>Building core-image-minimal:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="background-color: #e3d2d2; color: #a61717;">Build</span> <span style="background-color: #e3d2d2; color: #a61717;">Configuration:</span>
<span style="color: #2db5b5;">BB_VERSION</span> = <span style="color: #bf7f0f;">"1.49.0"</span>
<span style="color: #2db5b5;">BUILD_SYS</span> = <span style="color: #bf7f0f;">"x86_64-linux"</span>
<span style="color: #2db5b5;">NATIVELSBSTRING</span> = <span style="color: #bf7f0f;">"opensuseleap-15.2"</span>
<span style="color: #2db5b5;">TARGET_SYS</span> = <span style="color: #bf7f0f;">"arm-oe-linux-gnueabi"</span>
<span style="color: #2db5b5;">MACHINE</span> = <span style="color: #bf7f0f;">"raspberrypi3"</span>
<span style="color: #2db5b5;">DISTRO</span> = <span style="color: #bf7f0f;">"nodistro"</span>
<span style="color: #2db5b5;">DISTRO_VERSION</span> = <span style="color: #bf7f0f;">"nodistro.0"</span>
<span style="color: #2db5b5;">TUNE_FEATURES</span> = <span style="color: #bf7f0f;">"arm vfp cortexa7 neon vfpv4 thumb callconvention-hard"</span>
<span style="color: #2db5b5;">TARGET_FPU</span> = <span style="color: #bf7f0f;">"hard"</span>
<span style="color: #2db5b5;">meta-raspberrypi</span> = <span style="color: #bf7f0f;">"master:361f42e346e59f3a3fafcfa4ab7c948969d5abf4"</span>
<span style="color: #2db5b5;">meta</span> = <span style="color: #bf7f0f;">"master:c58fcc1379ca5755a5b670f79b75e94370d4943c"</span>
<span style="color: #2db5b5;">meta-oe</span> = <span style="color: #bf7f0f;">"master:f03ad4971ed0b7cf34550a90ee3c0fa18f964533"</span>
</pre></td></tr></tbody></table></div>
<p>I end up with an image that has 40 packages:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="background-color: #e3d2d2; color: #a61717;">base-files_3.0.14-r89_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">base-passwd_3.5.29-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">busybox_1.32.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">busybox-syslog_1.32.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">busybox-udhcpc_1.32.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">eudev_3.2.9-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">glmark2_20201114+0+784aca755a-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">init-ifupdown_1.0-r7_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">initscripts-functions_1.0-r155_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">initscripts_1.0-r155_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">init-system-helpers-service_1.58-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">kbd_2.3.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">keymaps_1.0-r31_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">kmscube_git-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">ldconfig_2.32-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libblkid1_2.36-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libc6_2.32-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libdrm2_2.4.103-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libegl-mesa_2:20.2.4-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libexpat1_2.2.10-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libgbm1_2:20.2.4-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libgcc1_10.2.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libglapi0_2:20.2.4-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libgles2-mesa_2:20.2.4-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libjpeg62_1:2.0.6-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libkmod2_27-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libpng16-16_1.6.37-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libstdc++6_10.2.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libudev1_3.2.9-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libz1_1.2.11-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">mesa-megadriver_2:20.2.4-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">modutils-initscripts_1.0-r7_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">netbase_1:6.2-r0_all.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">packagegroup-core-boot_1.0-r17_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">run-postinsts_1.0-r10_all.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">sysvinit-inittab_2.88dsf-r10_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">sysvinit-pidof_2.97-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">sysvinit_2.97-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">update-alternatives-opkg_0.4.3-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">update-rc.d_0.8-r0_all.ipk</span>
</pre></td></tr></tbody></table></div>
<p>and my image size is 36MB:</p><blockquote style="border: medium none; margin: 0px 0px 0px 40px; padding: 0px;"><p style="text-align: left;"><span style="font-family: courier; font-size: x-small;">-rw-r--r-- 2 trevor users 36M Dec 16 23:40 tmp-glibc/deploy/images/raspberrypi3/core-image-minimal-raspberrypi3-20201217044019.rootfs.ext3</span></p></blockquote><p>The image is super-fast to boot to a cmdline, no X11 or Wayland is started, and from the serial console I can run kmscube:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-dbn4AgSF4b4/X9r0XAxAu5I/AAAAAAAAkQo/7RaJBajpLoII3nb3BYHlYi9mOzgO-7JFACLcBGAsYHQ/s416/IMG_100CANON_4167.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="221" data-original-width="416" src="https://1.bp.blogspot.com/-dbn4AgSF4b4/X9r0XAxAu5I/AAAAAAAAkQo/7RaJBajpLoII3nb3BYHlYi9mOzgO-7JFACLcBGAsYHQ/s320/IMG_100CANON_4167.JPG" width="320" /></a></div><p><br /></p><p>glmark2-es2-drm (OpenGL ES 2):</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-STX2VcKtbEA/X9r0iLpHv4I/AAAAAAAAkQw/A4vDNfa6Qa4QrUZ7dhE0Wzq4gKW441y3wCLcBGAsYHQ/s400/IMG_100CANON_4174.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="215" data-original-width="400" src="https://1.bp.blogspot.com/-STX2VcKtbEA/X9r0iLpHv4I/AAAAAAAAkQw/A4vDNfa6Qa4QrUZ7dhE0Wzq4gKW441y3wCLcBGAsYHQ/s320/IMG_100CANON_4174.JPG" width="320" /></a></div><br /><p></p><p>or glmark2-drm (OpenGL):</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-eZn_rAe9OQc/X9r0fKq3QYI/AAAAAAAAkQs/1agaFHKGRC43g-ced3QEtqFH7vXgLFAkwCLcBGAsYHQ/s307/IMG_100CANON_4169.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="205" data-original-width="307" src="https://1.bp.blogspot.com/-eZn_rAe9OQc/X9r0fKq3QYI/AAAAAAAAkQs/1agaFHKGRC43g-ced3QEtqFH7vXgLFAkwCLcBGAsYHQ/s0/IMG_100CANON_4169.JPG" /></a></div><p></p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-4450554968431557352020-12-15T14:42:00.001-05:002022-03-21T08:44:26.742-04:00userland graphics with OpenEmbedded/Yocto<p>When the RaspberryPi was first released (Apr 2012), support for its GPU was provided by a <a href="https://github.com/raspberrypi/firmware" target="_blank">binary blob</a> that was accessible via a library called "userland". Originally this glue library was supplied in binary format, but on <a href="https://www.raspberrypi.org/blog/open-source-arm-userspace/" target="_blank">Oct 24, 2012</a> the <a href="https://github.com/raspberrypi/userland" target="_blank">sources for the userland glue library were made available</a>. The userland library exposes support for a number of GPU APIs including: EGL, GLESv2, OpenVG, <a href="https://github.com/raspberrypi/userland/blob/master/README.md" target="_blank">and others</a>. Although many parts of this graphics stack are open-source, the core GPU code remains closed. Developers can call GLESv2 functions, for example, but aren't able to manage any of the GPU's resources.</p><p>Note that this graphics stack (binary blob + userland) is separate from the fully open-source support that has been added to Mesa since release 10.3.</p><p>There exist, therefore, two <i>providers</i> of GLES on a RaspberryPi system: the binary blob + userland, and full Mesa with support for vc4.</p><p>When using OpenEmbedded/Yocto to put together an image targetting a RaspberryPi device, if the intent is to run GLES applications, one must choose between these two graphics stacks. Otherwise it would be confusing for the build system to know which graphics stack was intended to provide GLES when linking a GLES application (e.g. glmark2).</p><p>An application using GLES usually sits atop a large number of libraries such as various X11 libraries, xcb, drm, EGL, GL/GLES, etc. which allow such an application to run in its own window as part of a windowing system. With the blob+userland option, a number of the libraries lower down in the stack are replaced by the dispmanx library. The dispmanx library doesn't sit on top of a window system; it prefers to take over the entire screen. As a result, running a graphics application with the blob+userland requires far fewer packages, doesn't require any x11/weston, and doesn't require any windowing environment.</p><p>The original RaspberryPis ran on 32-bit hardware. In an effort to prioritize backwards compatibility, even when the RaspberryPi migrated to 64-bit architectures, the official images continued to be built for 32-bit. As a result, most of the blob+userland code was written for, and assumes, a 32-bit environment.</p><p>There isn't very much information available regarding the dispmanx and userland libraries. The userland code comes with a bunch of sample applications that can be optionally built when building the library. A person named Andrew Duncan wrote a bunch of sample dispmanx applications which were published on github in a repository named <a href="https://github.com/AndrewFromMelbourne/raspidmx" target="_blank">raspidmx</a>. Also, the popular glmark2 code has an experimental fork with the changes necessary to run on top of dispmanx.</p><p>The best-known BSP layer with support for RaspberryPi includes the necessary knobs and buttons to allow you to create an image and select which graphics stack you would like to use. If you choose the blob+userland stack, support is also available for building the optional userland applications, for building raspidmx, as well as a version of glmark2 that runs on dispmanx.</p><p>Assuming you're already familiar with most of the basics of setting up an OpenEmbedded/Yocto build, for this test (at a minimum) you'll need:</p><p></p><ul style="text-align: left;"><li>bitbake</li><li>openembedded-core</li><li>meta-openembedded</li><li>meta-raspberrypi</li></ul><p></p><p>Once you've cloned those repositories and setup your build environment, in order to use the blob+userland graphics stack as well as build all the sample applications mentioned above, my conf/local.conf has the following changes and additions:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">MACHINE</span> = <span style="color: #bf7f0f;">"raspberrypi3"</span>
<span style="color: #2db5b5;">DISABLE_VC4GRAPHICS</span> = <span style="color: #bf7f0f;">"1"</span>
<span style="color: #2db5b5;">DISTRO_FEATURES</span> += <span style="color: #bf7f0f;">"x11 dispmanx"</span>
<span style="color: #2db5b5;">CORE_IMAGE_EXTRA_INSTALL</span> += <span style="color: #bf7f0f;">"glmark2 raspidmx"</span>
<span style="color: #2db5b5;">PACKAGECONFIG_append_pn-userland</span> = <span style="color: #bf7f0f;">" allapps"</span>
<span style="color: #2db5b5;">PACKAGECONFIG_pn-glmark2</span> = <span style="color: #bf7f0f;">"dispmanx"</span>
<span style="color: #2db5b5;">ENABLE_UART</span> = <span style="color: #bf7f0f;">"1"</span>
<span style="color: #2db5b5;">GPU_MEM</span> = <span style="color: #bf7f0f;">"512"</span>
</pre></td></tr></tbody></table></div>
<p><b style="font-style: italic;">NOTE</b>: this is not my entire conf/local.conf, but rather just the things that I added or changed.</p><p></p><ul style="text-align: left;"><li>I plan to run this image on a Raspberry Pi 3 Model B V1.2, which has a 64-bit SoC, but I'm setting the MACHINE to "raspberrypi3" (i.e. the 32-bit machine)</li><li>On line 2 I'm explicitly disabling VC4GRAPHICS (which refers to the fully open-sourced Mesa support), thereby enabling support for the blob+userland graphics stack</li><li>Although I'm not building or including x11 support, when building glmark2 the code refers to some X11 headers (which might be an oversight on the part of the glmark2 code), in any case we need to add x11 to the DISTRO_FEATURES</li><li>On line 5 I'm adding the glmark2 (GLES) and raspidmx (dispmanx) sample applications to the image</li><li>On line 6 I'm enabling the optional build of sample dispmanx samples when building the userland library</li><li>On line 7 I'm making sure glmark2 is build with support for dispmanx</li><li>I enable the console UART on the Pi since I prefer working with the device over the console rather than plugging in a keyboard and mouse</li><li>On line 10 I increase the memory available to the GPU since one of the glmark2 tests fails with the default setting</li></ul><p></p><p>With my build properly configured, I proceed to build "core-image-minimal" as follows:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="background-color: #e3d2d2; color: #a61717;">Build</span> <span style="background-color: #e3d2d2; color: #a61717;">Configuration:</span>
<span style="color: #2db5b5;">BB_VERSION</span> = <span style="color: #bf7f0f;">"1.49.0"</span>
<span style="color: #2db5b5;">BUILD_SYS</span> = <span style="color: #bf7f0f;">"x86_64-linux"</span>
<span style="color: #2db5b5;">NATIVELSBSTRING</span> = <span style="color: #bf7f0f;">"opensuseleap-15.2"</span>
<span style="color: #2db5b5;">TARGET_SYS</span> = <span style="color: #bf7f0f;">"arm-oe-linux-gnueabi"</span>
<span style="color: #2db5b5;">MACHINE</span> = <span style="color: #bf7f0f;">"raspberrypi3"</span>
<span style="color: #2db5b5;">DISTRO</span> = <span style="color: #bf7f0f;">"nodistro"</span>
<span style="color: #2db5b5;">DISTRO_VERSION</span> = <span style="color: #bf7f0f;">"nodistro.0"</span>
<span style="color: #2db5b5;">TUNE_FEATURES</span> = <span style="color: #bf7f0f;">"arm vfp cortexa7 neon vfpv4 thumb callconvention-hard"</span>
<span style="color: #2db5b5;">TARGET_FPU</span> = <span style="color: #bf7f0f;">"hard"</span>
<span style="color: #2db5b5;">meta-raspberrypi</span> = <span style="color: #bf7f0f;">"master:e4f5c32925fec90ff688e51197cb052fe12af82e"</span>
<span style="color: #2db5b5;">meta</span> = <span style="color: #bf7f0f;">"master:a55b01a3a1faf9a52d7edad074c76327f637aaa2"</span>
<span style="color: #2db5b5;">meta-oe</span> = <span style="color: #bf7f0f;">"master:936f2380bb5112721eec2db46eb35b5600ac28de"</span>
</pre></div>
<p>Note that bitbake is at checkout: 71aaac9efa69abbf6c27d174e0862644cbf674ef</p><p>When my build is done the only packages in my image are:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="background-color: #e3d2d2; color: #a61717;">base-files_3.0.14-r89_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">base-passwd_3.5.29-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">bash_5.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">busybox_1.32.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">busybox-syslog_1.32.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">busybox-udhcpc_1.32.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">eudev_3.2.9-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">glmark2_20201114+0+784aca755a-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">init-ifupdown_1.0-r7_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">initscripts-functions_1.0-r155_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">initscripts_1.0-r155_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">init-system-helpers-service_1.58-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">kbd_2.3.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">keymaps_1.0-r31_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">ldconfig_2.32-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libblkid1_2.36-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libc6_2.32-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libgcc1_10.2.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libjpeg62_1:2.0.6-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libkmod2_27-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libpng16-16_1.6.37-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libstdc++6_10.2.0-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libtinfo5_6.2-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">libz1_1.2.11-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">modutils-initscripts_1.0-r7_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">ncurses-terminfo-base_6.2-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">netbase_1:6.2-r0_all.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">packagegroup-core-boot_1.0-r17_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">raspidmx_0.0+git0+e2ee6faa0d-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">run-postinsts_1.0-r10_all.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">sysvinit-inittab_2.88dsf-r10_raspberrypi3.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">sysvinit-pidof_2.97-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">sysvinit_2.97-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">update-alternatives-opkg_0.4.3-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">update-rc.d_0.8-r0_all.ipk</span>
<span style="background-color: #e3d2d2; color: #a61717;">userland_20201027-r0_cortexa7t2hf-neon-vfpv4.ipk</span>
</pre></div>
<p>My entire image size is ~28MB:</p><blockquote style="border: medium none; margin: 0px 0px 0px 40px; padding: 0px;"><p style="text-align: left;"><span style="font-family: courier; font-size: x-small;">-rw-r--r-- 2 trevor users 28M Dec 15 14:23 core-image-minimal-raspberrypi3-20201215192252.rootfs.ext3</span></p></blockquote><p>Flashing to a µSD card and booting, from the serial console I am able to run the userland sample applications (not all of the sample apps are shown running here, but they all do run):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-tc6_XmTx47I/X9kO7MwT_oI/AAAAAAAAkOE/tu-FtuyevzoACXVu8lpkBvSKhm15kLc9wCLcBGAsYHQ/s634/userland-hello_tiger.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="406" data-original-width="634" height="205" src="https://1.bp.blogspot.com/-tc6_XmTx47I/X9kO7MwT_oI/AAAAAAAAkOE/tu-FtuyevzoACXVu8lpkBvSKhm15kLc9wCLcBGAsYHQ/w320-h205/userland-hello_tiger.jpg" title="hello_tiger.bin" width="320" /></a></div><br /><p>I can even run 2 of the sample userland applications at the same time:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-e2fYyGGBmgo/X9kPPR4WkaI/AAAAAAAAkOM/KMRD7UMLsh4KKPGGuz5tmbXRegl03qIwwCLcBGAsYHQ/s606/userland-hello_tiger-hello_dispmanx.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="338" data-original-width="606" height="178" src="https://1.bp.blogspot.com/-e2fYyGGBmgo/X9kPPR4WkaI/AAAAAAAAkOM/KMRD7UMLsh4KKPGGuz5tmbXRegl03qIwwCLcBGAsYHQ/w320-h178/userland-hello_tiger-hello_dispmanx.jpg" title="hello_tiger.bin and hello_dispmanx.bin" width="320" /></a></div><br /><p>I can run the raspidmx samples (not all are shown here, but they all do run):</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-soxb97L0iZE/X9kPmlpS4iI/AAAAAAAAkOU/dq_21SdMwqo0CYAdEWoILT2gdeFd3-3vACLcBGAsYHQ/s640/raspidmx-life.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="640" data-original-width="480" height="320" src="https://1.bp.blogspot.com/-soxb97L0iZE/X9kPmlpS4iI/AAAAAAAAkOU/dq_21SdMwqo0CYAdEWoILT2gdeFd3-3vACLcBGAsYHQ/s320/raspidmx-life.jpg" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-YstTSIt2rrA/X9kPnyDVwNI/AAAAAAAAkOY/S7kf6UyHvbQi6gRw3hiHbjYDkyICBFR2ACLcBGAsYHQ/s640/raspidmx-game.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="640" data-original-width="480" height="320" src="https://1.bp.blogspot.com/-YstTSIt2rrA/X9kPnyDVwNI/AAAAAAAAkOY/S7kf6UyHvbQi6gRw3hiHbjYDkyICBFR2ACLcBGAsYHQ/w240-h320/raspidmx-game.jpg" title="game" width="240" /></a></div><br /><p><br /></p><p>And I can run glmark2-es2-dispmanx:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-J5px8COFDP8/X9kPynjbfZI/AAAAAAAAkOc/MXPcSWiZPg87l_YI1t77Cw5PR7rVk_qMACLcBGAsYHQ/s640/glmark2-es2-dispmanx.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" src="https://1.bp.blogspot.com/-J5px8COFDP8/X9kPynjbfZI/AAAAAAAAkOc/MXPcSWiZPg87l_YI1t77Cw5PR7rVk_qMACLcBGAsYHQ/s320/glmark2-es2-dispmanx.jpg" width="320" /></a></div><br /><p><br /></p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-50270360709775368382020-10-19T00:52:00.001-04:002022-03-21T08:43:41.493-04:00Writing Software for your Embedded Device with OpenEmbedded<p>In my <a href="https://twoerner.blogspot.com/2020/10/pimoroni-automation-hat-meets.html" target="_blank">last post</a> we built our own, very up-to-date, image for our target device (a RaspberryPi3 fitted with Pimoroni's Automation-HAT) using Yocto/OE and poky. This image included the latest revisions of Pimoroni's Python libraries for driving the Automation-HAT, thanks to the enormous amount of help <i>devtool</i> provides for creating new recipes for existing code available in repositories.</p><p>If there exists a repository of code you'd like to add to your image, you need a <i>recipe</i> that will fetch, build, deploy, etc the software. If you're lucky a recipe will already exist in the <a href="http://layers.openembedded.org/" target="_blank">layer index</a>. If you have to write your own recipe, <i>devtool</i> is a powerful and invaluable tool. Simply invoke <i>devtool</i>, choose a recipe name, point <i>devtool</i> at the repository, and it does much of the work for you (including identifying dependencies)! The tooling understands dozens of fetchers for common repository types (git, cvs, clearcase, perforce, wget, bzr, etc…), and it provides dozens of handlers for dealing with various build systems (autotools, make, cmake, meson, npm, setuptools, etc…). As you can imagine, this exercise becomes more challenging if the software isn't using a common build system, or isn't using it correctly.</p><p>But what if the code doesn't already exist? If you're creating your own product and writing your own software, there will not be any pre-existing repository at which you can point <i>devtool</i>. This is the scenario we're going to focus on in this post. The assumptions are that you're writing code that needs to be compiled (i.e. not interpreted), and that you're using a much more powerful build host for development therefore you will need to cross-compile your code. Since the hardware we're using has some "toys" to "play" with (i.e. LEDs, ADCs, relays, inputs, and outputs), the goal of our code will be to "play" with some of the "toys" found on the Automation-HAT. Also, since my goal is to focus on cross-compiling and embedded development, I'm going to ignore the pre-exisiting python libraries that are available for this hardware.</p><p>There are two broad scenarios:<br /></p><ol style="text-align: left;"><li>you are comfortable using OpenEmbedded and would like to create an image and write the software entirely on your own host machine</li><li>you are working as part of a team and have no interest in the overall image or knowing how the images are created, you only want to focus on writing the software</li></ol><p style="text-align: left;">In either case all developers need access to the cross-development tools that will be used to build the final image. This will help alleviate many of the "gotchas" that crop up late in the development cycle when code gets integrated into the final image. If developers are using different versions of a given compiler, it's not uncommon for newer versions of the same tool to find more problems/errors with the code than older versions, or for newer versions to compile the code differently or make different assumptions. Having all developers use the same versions of all the same tools and libraries throughout the development process goes a long way towards improving your release process and improving the quality of your testing.</p><p style="text-align: left;">As I mentioned in my previous post, I like to start small and make incremental changes as I go. Which means I like to build my code often and test it often (preferably on the device itself). So let's start with a "Hello, world!". In any "good" software project, the code is but one component of the overall effort. Therefore I like to put my code in a <i>src</i> subdirectory of my project (…in anticipation of a <i>doc</i> directory for documentation, a <i>test</i> subdirectory for tests, etc).</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> mkdir src
<span style="color: #348c00;">$</span> cd src
<span style="color: #348c00;">$</span> vi i2ctest.c
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">…and for the code…</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;">/*</span>
<span style="color: #777777; font-style: italic;"> * Copyright (C) 2020 Trevor Woerner <twoerner@gmail.com></span>
<span style="color: #777777; font-style: italic;"> */</span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><stdio.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #6ab825; font-weight: bold;">int</span>
<span style="color: #447fcf;">main</span> (<span style="color: #6ab825; font-weight: bold;">void</span>)
{
printf(<span style="color: #bf7f0f;">"Hello, world!\n"</span>);
<span style="color: #6ab825; font-weight: bold;">return</span> <span style="color: #3677a9;">0</span>;
}
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">As good developers we should be thinking about using a standard build system. There are many from which to choose; for this example I'm going to select the <i>autotools</i>. In order for our code to be built using the <i>autotools</i> we need to put project-specific metadata in various files which the <i>autotools</i> process so we can then use regular <i>make</i> to build.</p><p style="text-align: left;">In the top-level directory we need to create:</p><p></p>
<p style="text-align: left;"></p><ol style="text-align: left;"><li>the project's <span style="font-family: courier; font-size: x-small;">configure.ac</span> (which eventually gets transformed into the familiar <span style="font-family: courier; font-size: x-small;">./configure</span> script)<br />
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;">dnl Copyright (C) 2020 Trevor Woerner <twoerner@gmail.com></span>
AC_PREREQ(2.57)
AC_INIT([automationhat-doodles], 0.1.0, twoerner@gmail.com, automationhat-doodles)
AC_CONFIG_SRCDIR(src/i2ctest.c)
AC_CONFIG_AUX_DIR(cfg)
AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-bzip2 1.9])
AM_CONFIG_HEADER(cfg/config.h)
SUBDIRS="src"
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl checks for programs</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_PROG_CC
AC_PROG_CPP
AC_PROG_MAKE_SET
AC_PROG_INSTALL
AC_PROG_LN_S
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl checks for header files</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_HEADER_STDC
AC_CHECK_HEADERS(stdio.h stdlib.h string.h unistd.h fcntl.h errno.h getopt.h)
AC_CHECK_HEADERS(sys/types.h sys/stat.h sys/ioctl.h linux/i2c.h linux/i2c-dev.h)
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl checks for typedefs, structs, and</span>
<span style="color: #777777; font-style: italic;">dnl compiler characteristics</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_TYPE_SIZE_T
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl other stuff</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_SUBST(SUBDIRS)
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl output</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_OUTPUT(Makefile
cfg/Makefile
src/Makefile)
</pre></td></tr></tbody></table></div>
<br /></li><li>the top-level Makefile.am<br />
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5
6
7</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;">## Copyright (C) 2020 Trevor Woerner <twoerner@gmail.com></span>
<span style="color: #777777; font-style: italic;">########################</span>
<span style="color: #777777; font-style: italic;">## top-level Makefile.am</span>
<span style="color: #777777; font-style: italic;">########################</span>
SUBDIRS = @SUBDIRS@
DIST_SUBDIRS = cfg @SUBDIRS@
</pre></td></tr></tbody></table></div>
</li></ol><p></p><p style="text-align: left;">I prefer to put the configuration-related things into a separate <span style="font-family: courier; font-size: x-small;">cfg</span> directory, so I create that directory and create a <span style="font-family: courier; font-size: x-small;">Makefile.am</span> in there too:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> mkdir cfg
<span style="color: #348c00;">$</span> vi cfg/Makefile.am
</pre></td></tr></tbody></table></div>
<p><span style="text-align: left;"></span></p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5
6</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;">## Copyright (C) 2020 Trevor Woerner <twoerner@gmail.com></span>
<span style="color: #777777; font-style: italic;">########################</span>
<span style="color: #777777; font-style: italic;"># cfg/Makefile.am</span>
<span style="color: #777777; font-style: italic;">########################</span>
SUBDIRS =
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Finally, we need a <span style="font-family: courier; font-size: x-small;">Makefile.am</span> in the <span style="font-family: courier; font-size: x-small;">src</span> directory as well:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;">## Copyright (C) 2020 Trevor Woerner <twoerner@gmail.com></span>
<span style="color: #777777; font-style: italic;">########################</span>
<span style="color: #777777; font-style: italic;">## src/Makefile.am</span>
<span style="color: #777777; font-style: italic;">########################</span>
SUBDIRS =
AM_CFLAGS = -Wall -Werror -Wextra -Wconversion -Wreturn-type -Wstrict-prototypes
bin_PROGRAMS = i2ctest
i2ctest_SOURCES = i2ctest.c
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Our code is all ready to go, our target device is standing by, now how do we cross-compile this code with the tools we've used to create the rest of our image, and how can we test the code to verify it's working correctly? Earlier I outlined two scenarios: you're either going to be both writing some code and building the images, or you're only interested in writing code. Similarly there is a solution for each scenario:</p><p style="text-align: left;"></p><ol style="text-align: left;"><li>use <i>devtool</i> to help write a recipe for the code you're writing (which is very similar to how we used it in my previous blog post) the difference is that instead of pointing <i>devtool</i> to a repository "out there" on the internet, you point it at the top-level directory of wherever you're writing your code</li><li>the person who is creating the images and running <i>bitbake</i> generates an SDK and hands it to the developer who uses it like any other SDK</li></ol><h2 style="text-align: left;">Image And Code</h2><p style="text-align: left;">As before, in this case we can use <i>devtool</i> to create a recipe for us and simply build our code like any other package:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool add automationhat-doodles /opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Creating workspace layer in /z/build-master/6951/automation-hat/build/workspace</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Recipe /z/build-master/6951/automation-hat/poky/build/workspace/recipes/automationhat-doodles/automationhat-doodles_0.1.0.bb has been automatically created; further editing may be required to make it fully functional</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Looking at the workspace:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> tree workspace
<span style="color: #777777;">workspace</span>
<span style="color: #777777;">├── README</span>
<span style="color: #777777;">├── appends</span>
<span style="color: #777777;">│ └── automationhat-doodles_0.1.0.bbappend</span>
<span style="color: #777777;">├── conf</span>
<span style="color: #777777;">│ └── layer.conf</span>
<span style="color: #777777;">└── recipes</span>
<span style="color: #777777;"> └── automationhat-doodles</span>
<span style="color: #777777;"> └── automationhat-doodles_0.1.0.bb</span>
<span style="color: #777777;">4 directories, 4 files…</span></pre></td></tr></tbody></table></div><p style="text-align: left;">…the <span style="font-family: courier; font-size: x-small;">appends</span>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #6ab825; font-weight: bold;">inherit</span> <span style="color: #447fcf; text-decoration: underline;">externalsrc</span>
<span style="color: #2db5b5;">EXTERNALSRC</span> = <span style="color: #bf7f0f;">"/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles"</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">…and the raw recipe <i>devtool</i> created for us:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;"># Recipe created by recipetool</span>
<span style="color: #777777; font-style: italic;"># This is the basis of a recipe and may need further editing in order to be fully functional.</span>
<span style="color: #777777; font-style: italic;"># (Feel free to remove these comments when editing.)</span>
<span style="color: #777777; font-style: italic;"># Unable to find any files that looked like license statements. Check the accompanying</span>
<span style="color: #777777; font-style: italic;"># documentation and source headers and set LICENSE and LIC_FILES_CHKSUM accordingly.</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #777777; font-style: italic;"># NOTE: LICENSE is being set to "CLOSED" to allow you to at least start building - if</span>
<span style="color: #777777; font-style: italic;"># this is not accurate with respect to the licensing of the software being built (it</span>
<span style="color: #777777; font-style: italic;"># will not be in most cases) you must specify the correct value before using this</span>
<span style="color: #777777; font-style: italic;"># recipe for anything other than initial testing/development!</span>
<span style="color: #2db5b5;">LICENSE</span> = <span style="color: #bf7f0f;">"CLOSED"</span>
<span style="color: #2db5b5;">LIC_FILES_CHKSUM</span> = <span style="color: #bf7f0f;">""</span>
<span style="color: #777777; font-style: italic;"># No information for SRC_URI yet (only an external source tree was specified)</span>
<span style="color: #2db5b5;">SRC_URI</span> = <span style="color: #bf7f0f;">""</span>
<span style="color: #777777; font-style: italic;"># NOTE: if this software is not capable of being built in a separate build directory</span>
<span style="color: #777777; font-style: italic;"># from the source, you should replace autotools with autotools-brokensep in the</span>
<span style="color: #777777; font-style: italic;"># inherit line</span>
<span style="color: #6ab825; font-weight: bold;">inherit</span> <span style="color: #447fcf; text-decoration: underline;">autotools</span>
<span style="color: #777777; font-style: italic;"># Specify any options you want to pass to the configure script using EXTRA_OECONF:</span>
<span style="color: #2db5b5;">EXTRA_OECONF</span> = <span style="color: #bf7f0f;">""</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Everything we have is enough to build our software, no changes required:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool build automationhat-doodles
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% | | ETA: --:--:--</span>
<span style="color: #777777;">Loaded 0 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:13</span>
<span style="color: #777777;">Parsing of 2044 .bb files complete (0 cached, 2044 parsed). 3215 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">Removing 1 recipes from the cortexa53 sysroot: 100% |###########################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Removing 1 recipes from the raspberrypi3_64 sysroot: 100% |#####################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:03</span>
<span style="color: #777777;">Loaded 3214 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2044 .bb files complete (2043 cached, 1 parsed). 3215 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">meta-oe </span>
<span style="color: #777777;">meta-python = "master:86a7820b7964ff91d7a26ac5c506e83292e347a3"</span>
<span style="color: #777777;">devtool-additions = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Found 0 Missed 0 Current 116 (0% match, 100% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: automationhat-doodles: compiling from external source tree /opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 495 tasks of which 487 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 1 seconds</span>
<span style="color: #777777;">NOTE: Build completion summary:</span>
<span style="color: #777777;">NOTE: do_populate_sysroot: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_deploy_source_date_epoch: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_package: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_packagedata: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Success! The exact same build system that OE created to generate our entire image has now been used in exactly the same way to build the code we just wrote. As a developer I don't have to know anything about having to find or build an appropriate cross-compiler, or worry about whether I've passed the correct flags to the cross-compiler to ensure my build is using the correct headers (for example).</p><p style="text-align: left;">Now we need to get our code over to the target device so we can test it. In theory we could generate a new image with each build and test our code that way. That would create quite a long development cycle! Provided we have networking working on the target and an <i>ssh</i> server running, we could just <i>scp</i> the file over and run it. With a simple program like this one, the proposed solution would work fine. But as the code gets more complicated (e.g. multiple pieces, libraries, etc) copying everything over could increase the possibilities of errors. Also, once we're done testing a given build, it would be nice of having a way to clear everything off the target device between uploads.</p><p style="text-align: left;">Once again, <i>devtool</i> is very helpful in this situation! It includes not only a <i>devtool deploy-target</i> command, but also a <i>devtool undeploy-target</i> command!</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool deploy-target automationhat-doodles root@10.0.0.50
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Previous bitbake instance shutting down?, waiting to retry...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#2)...</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 3209 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Parsing of 2040 .bb files complete (2039 cached, 1 parsed). 3210 targets, 165 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">tar: ./usr/bin/i2ctest: time stamp 2020-10-09 07:07:44.128603897 is 274194.69420039 s in the future</span>
<span style="color: #777777;">tar: ./usr/bin: time stamp 2020-10-09 07:07:44.128603897 is 274194.693851432 s in the future</span>
<span style="color: #777777;">tar: ./usr: time stamp 2020-10-09 07:07:44.124603877 is 274194.689302922 s in the future</span>
<span style="color: #777777;">tar: .: time stamp 2020-10-09 07:07:44.124603877 is 274194.689052297 s in the future</span>
<span style="color: #777777;">INFO: Successfully deployed /z/build-master/6951/automation-hat/build/tmp-glibc/work/cortexa53-oe-linux/automationhat-doodles/0.1.0-r0/image</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Once our code has been uploaded to the target we simply would run it on the target like any other piece of software:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@raspberrypi3-64:~#</span> i2ctest
<span style="color: #777777;">Hello, world!</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Once we're done with our tests we clean up the target like so:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool undeploy-target automationhat-doodles root@10.0.0.50
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Successfully undeployed automationhat-doodles</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;"><i style="font-weight: bold;">NOTE</i>: you don't need to <i>undeploy-target</i> after each test. If you're compiling and testing in a tight loop you can simply <i>devtool deploy-target</i> repeatedly. The first thing a <i>devtool deploy-target</i> does is to check for and <i>devtool undeploy-target</i> any previous deploys of the same package. It keeps track of all the files that were copied over on each deploy, so that they can all be removed either when you <i>undeploy-target</i> explicitly, or when your next <i>deploy-target</i> implicitly removes the previous.</p><h2 style="text-align: left;">Code Only</h2><p style="text-align: left;">If you have a team of developers, it is possible to extract the cross-development tools (and all the other relevant pieces) from your build and bundle everything together into an SDK. Using this SDK, the developers will be using the same tools as the image build, and all your developers will be using the same tools. Additionally, the SDK you create will have all the correct header files for all of the components of the software that forms your specific image!</p><p style="text-align: left;">An off-the-shelf SDK you find randomly on the internet will advertise the version of the compiler it's using, but what versions of which other packages are included? Which C library is it using, and what version? Which kernel headers were used? And what if your application sits on top of a bunch of high-level libraries (i.e. a GUI application)? With many off-the-shelf SDKs, getting the flags right to ensure your host system isn't contaminating your cross-build is often left as an exercise for the user! The SDK you generate from your OE image takes care of all those details for you.</p><p style="text-align: left;">To generate an SDK from any of your specific images, build the image with <i>bitbake</i> as usual, but indicate you want the <i>populate_sdk</i> task run specifically:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake core-image-full-cmdline -c populate_sdk
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 3214 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2044 .bb files complete (2043 cached, 1 parsed). 3215 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">meta-oe </span>
<span style="color: #777777;">meta-python = "master:86a7820b7964ff91d7a26ac5c506e83292e347a3"</span>
<span style="color: #777777;">devtool-additions = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:02</span>
<span style="color: #777777;">Sstate summary: Wanted 464 Found 0 Missed 464 Current 982 (0% match, 67% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">WARNING: python3-sn3218-1.2.7+gitAUTOINC+d497c6e976-r0 do_packagedata: QA Issue: Package version for package python3-sn3218-src went backwards which would break package feeds (from 0:1.2.7+git999-r0 to 0:1.2.7+git0+d497c6e976-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: python3-sn3218-1.2.7+gitAUTOINC+d497c6e976-r0 do_packagedata: QA Issue: Package version for package python3-sn3218-dbg went backwards which would break package feeds (from 0:1.2.7+git999-r0 to 0:1.2.7+git0+d497c6e976-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: python3-sn3218-1.2.7+gitAUTOINC+d497c6e976-r0 do_packagedata: QA Issue: Package version for package python3-sn3218-staticdev went backwards which would break package feeds (from 0:1.2.7+git999-r0 to 0:1.2.7+git0+d497c6e976-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: python3-sn3218-1.2.7+gitAUTOINC+d497c6e976-r0 do_packagedata: QA Issue: Package version for package python3-sn3218-dev went backwards which would break package feeds (from 0:1.2.7+git999-r0 to 0:1.2.7+git0+d497c6e976-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: python3-sn3218-1.2.7+gitAUTOINC+d497c6e976-r0 do_packagedata: QA Issue: Package version for package python3-sn3218-doc went backwards which would break package feeds (from 0:1.2.7+git999-r0 to 0:1.2.7+git0+d497c6e976-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: python3-sn3218-1.2.7+gitAUTOINC+d497c6e976-r0 do_packagedata: QA Issue: Package version for package python3-sn3218-locale went backwards which would break package feeds (from 0:1.2.7+git999-r0 to 0:1.2.7+git0+d497c6e976-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: python3-sn3218-1.2.7+gitAUTOINC+d497c6e976-r0 do_packagedata: QA Issue: Package version for package python3-sn3218 went backwards which would break package feeds (from 0:1.2.7+git999-r0 to 0:1.2.7+git0+d497c6e976-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+gitAUTOINC+a41084cb4d-r0 do_packagedata: QA Issue: Package version for package automation-hat-src went backwards which would break package feeds (from 0:0.2.3+git999-r0 to 0:0.2.3+git0+a41084cb4d-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+gitAUTOINC+a41084cb4d-r0 do_packagedata: QA Issue: Package version for package automation-hat-dbg went backwards which would break package feeds (from 0:0.2.3+git999-r0 to 0:0.2.3+git0+a41084cb4d-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+gitAUTOINC+a41084cb4d-r0 do_packagedata: QA Issue: Package version for package automation-hat-staticdev went backwards which would break package feeds (from 0:0.2.3+git999-r0 to 0:0.2.3+git0+a41084cb4d-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+gitAUTOINC+a41084cb4d-r0 do_packagedata: QA Issue: Package version for package automation-hat-dev went backwards which would break package feeds (from 0:0.2.3+git999-r0 to 0:0.2.3+git0+a41084cb4d-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+gitAUTOINC+a41084cb4d-r0 do_packagedata: QA Issue: Package version for package automation-hat-doc went backwards which would break package feeds (from 0:0.2.3+git999-r0 to 0:0.2.3+git0+a41084cb4d-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+gitAUTOINC+a41084cb4d-r0 do_packagedata: QA Issue: Package version for package automation-hat-locale went backwards which would break package feeds (from 0:0.2.3+git999-r0 to 0:0.2.3+git0+a41084cb4d-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+gitAUTOINC+a41084cb4d-r0 do_packagedata: QA Issue: Package version for package automation-hat went backwards which would break package feeds (from 0:0.2.3+git999-r0 to 0:0.2.3+git0+a41084cb4d-r0) [version-going-backwards]</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 4171 tasks of which 3016 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 15 seconds</span>
<span style="color: #777777;">NOTE: Build completion summary:</span>
<span style="color: #777777;">NOTE: do_populate_sysroot: 0.0% sstate reuse(0 setscene, 67 scratch)</span>
<span style="color: #777777;">NOTE: do_deploy_source_date_epoch: 0.0% sstate reuse(0 setscene, 98 scratch)</span>
<span style="color: #777777;">NOTE: do_package: 0.0% sstate reuse(0 setscene, 99 scratch)</span>
<span style="color: #777777;">NOTE: do_packagedata: 0.0% sstate reuse(0 setscene, 99 scratch)</span>
<span style="color: #777777;">NOTE: do_package_write_ipk: 0.0% sstate reuse(0 setscene, 99 scratch)</span>
<span style="color: #777777;">Summary: There were 14 WARNING messages shown.</span>
</pre></td></tr></tbody></table></div>
<p></p><p style="text-align: left;">The resulting SDK is found in <span style="font-family: courier; font-size: x-small;">${TMPDIR}/deploy/sdk</span>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5
6</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> ls -lh tmp/deploy/sdk/
<span style="color: #777777;">total 254M</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 9.4K Oct 18 00:33 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.host.manifest</span>
<span style="color: #777777;">-rwxr-xr-x 2 trevor users 253M Oct 18 00:35 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.sh</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 160K Oct 18 00:32 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.target.manifest</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 339K Oct 18 00:32 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.testdata.json</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">The SDK is bundled as a self-extracting shell script. Give the script to your developers (in this case it's the <span style="font-family: courier; font-size: x-small;">poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.sh</span> file) and have them simply execute the file. It will ask the person installing the file for a target location. In the following example, I've decided to install the SDK into the directory <span style="font-family: courier; font-size: x-small;">/opt/toolchains/automation-hat/poky/sdk</span>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> ./poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.sh
<span style="color: #777777;">Poky (Yocto Project Reference Distro) SDK installer version 3.1+snapshot</span>
<span style="color: #777777;">========================================================================</span>
<span style="color: #777777;">Enter target directory for SDK (default: /opt/poky/3.1+snapshot): </span>/opt/toolchains/automation-hat/poky
<span style="color: #777777;">You are about to install the SDK to "/opt/toolchains/automation-hat/poky". Proceed [Y/n]? </span>Y
<span style="color: #777777;">Extracting SDK..................................................................................done</span>
<span style="color: #777777;">Setting it up...done</span>
<span style="color: #777777;">SDK has been successfully set up and is ready to be used.</span>
<span style="color: #777777;">Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.</span>
<span style="color: #777777;"> $ . /opt/toolchains/automation-hat/poky/environment-setup-cortexa53-poky-linux</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">As the installer so helpfully reminds us, anytime you want to use the SDK you just installed, in a fresh shell environment you'll have to <i>source</i> the environment file in order to correctly use the cross-compiler. In the following example I'm going to use the SDK I just installed in order to build my code. I'll start a new shell for this demonstration, but this isn't shown.</p><p style="text-align: left;"><i style="font-weight: bold;">NOTE</i>: in the following example my SDK is installed to <span style="font-family: courier; font-size: x-small;">/opt/toolchains/automation-hat/poky/sdk</span> my source code is found in <span style="font-family: courier; font-size: x-small;">/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles</span> and I will be building my code "out of tree" at <span style="font-family: courier; font-size: x-small;">/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build</span>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> cd /opt/toolchains/automation-hat/poky/sdk/
<span style="color: #348c00;">$</span> . ./environment-setup-cortexa53-poky-linux
<span style="color: #348c00;">$</span> export <span style="color: #2db5b5;">PS1</span>=<span style="color: #bf7f0f;">"${</span><span style="color: #2db5b5;">PS1</span><span style="color: #bf7f0f;">}sdk> "</span>
<span style="color: #348c00;">$ sdk></span> cd /opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/
<span style="color: #348c00;">$ sdk></span> autoreconf -i
<span style="color: #777777;">configure.ac:15: installing 'cfg/compile'</span>
<span style="color: #777777;">configure.ac:7: installing 'cfg/install-sh'</span>
<span style="color: #777777;">configure.ac:7: installing 'cfg/missing'</span>
<span style="color: #777777;">src/Makefile.am: installing 'cfg/depcomp'</span>
<span style="color: #348c00;">$ sdk></span> mkdir _build
<span style="color: #348c00;">$ sdk></span> cd _build
<span style="color: #348c00;">$ sdk></span> ../configure --host=x86_64
<span style="color: #777777;">configure: loading site script /opt/toolchains/automation-hat/poky/sdk/site-config-cortexa53-poky-linux</span>
<span style="color: #777777;">checking for a BSD-compatible install... /usr/bin/install -c</span>
<span style="color: #777777;">checking whether build environment is sane... yes</span>
<span style="color: #777777;">checking for x86_64-strip... aarch64-poky-linux-strip</span>
<span style="color: #777777;">checking for a thread-safe mkdir -p... /usr/bin/mkdir -p</span>
<span style="color: #777777;">checking for gawk... gawk</span>
<span style="color: #777777;">checking whether make sets $(MAKE)... yes</span>
<span style="color: #777777;">checking whether make supports nested variables... yes</span>
<span style="color: #777777;">checking for x86_64-gcc... aarch64-poky-linux-gcc -mcpu=cortex-a53 -march=armv8-a+crc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/toolchains/automation-hat/poky/sdk/sysroots/cortexa53-poky-linux</span>
<span style="color: #777777;">checking whether the C compiler works... yes</span>
<span style="color: #777777;">checking for C compiler default output file name... a.out</span>
<span style="color: #777777;">checking for suffix of executables... </span>
<span style="color: #777777;">checking whether we are cross compiling... yes</span>
<span style="color: #777777;">checking for suffix of object files... o</span>
<span style="color: #777777;">checking whether we are using the GNU C compiler... yes</span>
<span style="color: #777777;">checking whether aarch64-poky-linux-gcc -mcpu=cortex-a53 -march=armv8-a+crc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/toolchains/automation-hat/poky/sdk/sysroots/cortexa53-poky-linux accepts -g... yes</span>
<span style="color: #777777;">checking for aarch64-poky-linux-gcc -mcpu=cortex-a53 -march=armv8-a+crc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/toolchains/automation-hat/poky/sdk/sysroots/cortexa53-poky-linux option to accept ISO C89... none needed</span>
<span style="color: #777777;">checking whether aarch64-poky-linux-gcc -mcpu=cortex-a53 -march=armv8-a+crc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/toolchains/automation-hat/poky/sdk/sysroots/cortexa53-poky-linux understands -c and -o together... yes</span>
<span style="color: #777777;">checking whether make supports the include directive... yes (GNU style)</span>
<span style="color: #777777;">checking dependency style of aarch64-poky-linux-gcc -mcpu=cortex-a53 -march=armv8-a+crc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/toolchains/automation-hat/poky/sdk/sysroots/cortexa53-poky-linux... gcc3</span>
<span style="color: #777777;">checking how to run the C preprocessor... aarch64-poky-linux-gcc -E -mcpu=cortex-a53 -march=armv8-a+crc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/toolchains/automation-hat/poky/sdk/sysroots/cortexa53-poky-linux</span>
<span style="color: #777777;">checking whether make sets $(MAKE)... (cached) yes</span>
<span style="color: #777777;">checking whether ln -s works... yes</span>
<span style="color: #777777;">checking for grep that handles long lines and -e... /usr/bin/grep</span>
<span style="color: #777777;">checking for egrep... /usr/bin/grep -E</span>
<span style="color: #777777;">checking for ANSI C header files... yes</span>
<span style="color: #777777;">checking for sys/types.h... yes</span>
<span style="color: #777777;">checking for sys/stat.h... yes</span>
<span style="color: #777777;">checking for stdlib.h... yes</span>
<span style="color: #777777;">checking for string.h... yes</span>
<span style="color: #777777;">checking for memory.h... yes</span>
<span style="color: #777777;">checking for strings.h... yes</span>
<span style="color: #777777;">checking for inttypes.h... yes</span>
<span style="color: #777777;">checking for stdint.h... yes</span>
<span style="color: #777777;">checking for unistd.h... yes</span>
<span style="color: #777777;">checking stdio.h usability... yes</span>
<span style="color: #777777;">checking stdio.h presence... yes</span>
<span style="color: #777777;">checking for stdio.h... yes</span>
<span style="color: #777777;">checking for stdlib.h... (cached) yes</span>
<span style="color: #777777;">checking for string.h... (cached) yes</span>
<span style="color: #777777;">checking for unistd.h... (cached) yes</span>
<span style="color: #777777;">checking fcntl.h usability... yes</span>
<span style="color: #777777;">checking fcntl.h presence... yes</span>
<span style="color: #777777;">checking for fcntl.h... yes</span>
<span style="color: #777777;">checking errno.h usability... yes</span>
<span style="color: #777777;">checking errno.h presence... yes</span>
<span style="color: #777777;">checking for errno.h... yes</span>
<span style="color: #777777;">checking getopt.h usability... yes</span>
<span style="color: #777777;">checking getopt.h presence... yes</span>
<span style="color: #777777;">checking for getopt.h... yes</span>
<span style="color: #777777;">checking for sys/types.h... (cached) yes</span>
<span style="color: #777777;">checking for sys/stat.h... (cached) yes</span>
<span style="color: #777777;">checking sys/ioctl.h usability... yes</span>
<span style="color: #777777;">checking sys/ioctl.h presence... yes</span>
<span style="color: #777777;">checking for sys/ioctl.h... yes</span>
<span style="color: #777777;">checking linux/i2c.h usability... yes</span>
<span style="color: #777777;">checking linux/i2c.h presence... yes</span>
<span style="color: #777777;">checking for linux/i2c.h... yes</span>
<span style="color: #777777;">checking linux/i2c-dev.h usability... yes</span>
<span style="color: #777777;">checking linux/i2c-dev.h presence... yes</span>
<span style="color: #777777;">checking for linux/i2c-dev.h... yes</span>
<span style="color: #777777;">checking for size_t... yes</span>
<span style="color: #777777;">configure: creating ./config.status</span>
<span style="color: #777777;">config.status: creating Makefile</span>
<span style="color: #777777;">config.status: creating cfg/Makefile</span>
<span style="color: #777777;">config.status: creating src/Makefile</span>
<span style="color: #777777;">config.status: creating cfg/config.h</span>
<span style="color: #777777;">config.status: executing depfiles commands</span>
<span style="color: #348c00;">$ sdk></span> make
<span style="color: #777777;">Making all in src</span>
<span style="color: #777777;">make[1]: Entering directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build/src'</span>
<span style="color: #777777;">make[2]: Entering directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build/src'</span>
<span style="color: #777777;">aarch64-poky-linux-gcc -mcpu=cortex-a53 -march=armv8-a+crc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/toolchains/automation-hat/poky/sdk/sysroots/cortexa53-poky-linux -DHAVE_CONFIG_H -I. -I../../src -I../cfg -Wall -Werror -Wextra -Wconversion -Wreturn-type -Wstrict-prototypes -O2 -pipe -g -feliminate-unused-debug-types -MT i2ctest.o -MD -MP -MF .deps/i2ctest.Tpo -c -o i2ctest.o ../../src/i2ctest.c</span>
<span style="color: #777777;">mv -f .deps/i2ctest.Tpo .deps/i2ctest.Po</span>
<span style="color: #777777;">aarch64-poky-linux-gcc -mcpu=cortex-a53 -march=armv8-a+crc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/toolchains/automation-hat/poky/sdk/sysroots/cortexa53-poky-linux -Wall -Werror -Wextra -Wconversion -Wreturn-type -Wstrict-prototypes -O2 -pipe -g -feliminate-unused-debug-types -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -Wl,-z,relro,-z,now -o i2ctest i2ctest.o </span>
<span style="color: #777777;">make[2]: Leaving directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build/src'</span>
<span style="color: #777777;">make[1]: Leaving directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build/src'</span>
<span style="color: #777777;">make[1]: Entering directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build'</span>
<span style="color: #777777;">make[1]: Nothing to be done for 'all-am'.</span>
<span style="color: #777777;">make[1]: Leaving directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build'</span>
<span style="color: #348c00;">$ sdk></span> file src/i2ctest
<span style="color: #777777;">src/i2ctest: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, BuildID[sha1]=47845aa25dff34453e7b1cb367c9b59883f8292c, for GNU/Linux 3.14.0, with debug_info, not stripped</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Yay! We've demonstrated generating an SDK tuned specifically for our image, giving this SDK to an independent developer, and that developer using the SDK on their own, separate machine, to cross-compile their code (in which they've used the <i>autotools</i> build system). This developer doesn't have OE installed on their system, isn't using OE to generate images, and is only focused on writing and cross-compiling their code for the target device.</p><p style="text-align: left;">Although this is a very small example, it does scale. If the code being written was, say, a GUI app that was using (for example) boost and GTK or Qt, simply add those libraries to your image and when you generate the SDK from this image, the SDK will include everything the developer needs to write their application (i.e. all the appropriate headers and cross-libraries).</p><p style="text-align: left;">On-target testing, though, is up to the developer. For a small example such as this, it wouldn't be too hard to copy the one file over and test it. But anything more complex could get messy. If only there was some way to create an SDK that also contained <i>devtool</i> …</p><h2 style="text-align: left;">Code Only… <i>extended</i></h2><p style="text-align: left;">Turns out there is a way:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake core-image-full-cmdline -c populate_sdk_ext
<span style="color: #777777;">Loading cache: 100% | | ETA: --:--:--</span>
<span style="color: #777777;">Loaded 0 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:14</span>
<span style="color: #777777;">Parsing of 2042 .bb files complete (0 cached, 2042 parsed). 3213 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">devtool-additions = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-oe </span>
<span style="color: #777777;">meta-python = "master:86a7820b7964ff91d7a26ac5c506e83292e347a3"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:03</span>
<span style="color: #777777;">Sstate summary: Wanted 2 Found 0 Missed 2 Current 1952 (0% match, 99% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 5092 tasks of which 5079 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 1 seconds</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Note, however, that there is a significant size difference between an SDK and an eSDK:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> ls -lh tmp/deploy/sdk/
<span style="color: #777777;">total 1.3G</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 9.4K Oct 18 00:33 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.host.manifest</span>
<span style="color: #777777;">-rwxr-xr-x 2 trevor users 253M Oct 18 00:35 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.sh</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 160K Oct 18 00:32 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.target.manifest</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 339K Oct 18 00:32 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-3.1+snapshot.testdata.json</span>
<span style="color: #777777;">-rw-r--r-- 1 trevor users 9.6K Oct 18 11:53 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-ext-3.1+snapshot.host.manifest</span>
<span style="color: #777777;">-rwxr-xr-x 2 trevor users 999M Oct 18 11:53 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-ext-3.1+snapshot.sh</span>
<span style="color: #777777;">-rw-r--r-- 1 trevor users 6.6K Oct 18 11:53 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-ext-3.1+snapshot.target.manifest</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 335K Oct 18 11:49 poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-ext-3.1+snapshot.testdata.json</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 6.6K Oct 18 02:06 x86_64-buildtools-nativesdk-standalone-3.1+snapshot-20201018.host.manifest</span>
<span style="color: #777777;">-rwxr-xr-x 2 trevor users 26M Oct 18 02:07 x86_64-buildtools-nativesdk-standalone-3.1+snapshot-20201018.sh</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 0 Oct 18 02:05 x86_64-buildtools-nativesdk-standalone-3.1+snapshot-20201018.target.manifest</span>
<span style="color: #777777;">-rw-r--r-- 2 trevor users 306K Oct 18 02:05 x86_64-buildtools-nativesdk-standalone-3.1+snapshot-20201018.testdata.json</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">You could install and use an eSDK exactly the same way you would use the regular SDK:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> /z/build-master/6951/automation-hat/poky/build/tmp/deploy/sdk/poky-glibc-x86_64-core-image-full-cmdline-cortexa53-raspberrypi3-64-toolchain-ext-3.1+snapshot.sh
<span style="color: #777777;">Poky (Yocto Project Reference Distro) Extensible SDK installer version 3.1+snapshot</span>
<span style="color: #777777;">===================================================================================</span>
<span style="color: #777777;">Enter target directory for SDK (default: ~/poky_sdk):</span> /opt/toolchains/automation-hat/poky/esdk
<span style="color: #777777;">You are about to install the SDK to "/opt/toolchains/automation-hat/poky/esdk". Proceed [Y/n]? </span>Y
<span style="color: #777777;">Extracting SDK................................................done</span>
<span style="color: #777777;">Setting it up...</span>
<span style="color: #777777;">Extracting buildtools...</span>
<span style="color: #777777;">Preparing build system...</span>
<span style="color: #777777;">Loading cache: 100% | | ETA: --:--:--</span>
<span style="color: #777777;">Parsing recipes: 100% |###############################################################| Time: 0:00:21</span>
<span style="color: #777777;">Initialising tasks: 100% |############################################################| Time: 0:00:02</span>
<span style="color: #777777;">Checking sstate mirror object availability: 100% |####################################| Time: 0:00:00</span>
<span style="color: #777777;">Loading cache: 100% |#################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Initialising tasks: 100% |############################################################| Time: 0:00:00</span>
<span style="color: #777777;">done</span>
<span style="color: #777777;">SDK has been successfully set up and is ready to be used.</span>
<span style="color: #777777;">Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.</span>
<span style="color: #777777;"> $ . /opt/toolchains/automation-hat/poky/esdk/environment-setup-cortexa53-poky-linux</span>
<span style="color: #348c00;">$</span> export <span style="color: #2db5b5;">PS1</span>=<span style="color: #bf7f0f;">"${</span><span style="color: #2db5b5;">PS1</span><span style="color: #bf7f0f;">}esdk> "</span>
<span style="color: #348c00;">$ esdk></span>
<span style="color: #348c00;">$ esdk></span> cd /opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/
<span style="color: #348c00;">$ esdk></span> autoreconf -i
<span style="color: #777777;">configure.ac:15: installing 'cfg/compile'</span>
<span style="color: #777777;">configure.ac:7: installing 'cfg/install-sh'</span>
<span style="color: #777777;">configure.ac:7: installing 'cfg/missing'</span>
<span style="color: #777777;">src/Makefile.am: installing 'cfg/depcomp'</span>
<span style="color: #348c00;">$ esdk></span> mkdir _build
<span style="color: #348c00;">$ esdk></span> cd _build
<span style="color: #348c00;">$ esdk></span> ../configure --host=x86_64
<span style="color: #777777;">configure: loading site script /usr/share/site/x86_64-unknown-linux-gnu</span>
<span style="color: #777777;">checking for a BSD-compatible install... /usr/bin/install -c</span>
<span style="color: #777777;">checking whether build environment is sane... yes</span>
<span style="color: #777777;">checking for x86_64-strip... no</span>
<span style="color: #777777;">checking for strip... strip</span>
<span style="color: #777777;">checking for a thread-safe mkdir -p... /usr/bin/mkdir -p</span>
<span style="color: #777777;">checking for gawk... gawk</span>
<span style="color: #777777;">checking whether make sets $(MAKE)... yes</span>
<span style="color: #777777;">checking whether make supports nested variables... yes</span>
<span style="color: #777777;">checking for x86_64-gcc... no</span>
<span style="color: #777777;">checking for gcc... gcc</span>
<span style="color: #777777;">checking whether the C compiler works... yes</span>
<span style="color: #777777;">checking for C compiler default output file name... a.out</span>
<span style="color: #777777;">checking for suffix of executables... </span>
<span style="color: #777777;">checking whether we are cross compiling... no</span>
<span style="color: #777777;">checking for suffix of object files... o</span>
<span style="color: #777777;">checking whether we are using the GNU C compiler... yes</span>
<span style="color: #777777;">checking whether gcc accepts -g... yes</span>
<span style="color: #777777;">checking for gcc option to accept ISO C89... none needed</span>
<span style="color: #777777;">checking whether gcc understands -c and -o together... yes</span>
<span style="color: #777777;">checking for style of include used by make... GNU</span>
<span style="color: #777777;">checking dependency style of gcc... gcc3</span>
<span style="color: #777777;">checking how to run the C preprocessor... gcc -E</span>
<span style="color: #777777;">checking whether make sets $(MAKE)... (cached) yes</span>
<span style="color: #777777;">checking whether ln -s works... yes</span>
<span style="color: #777777;">checking for grep that handles long lines and -e... /usr/bin/grep</span>
<span style="color: #777777;">checking for egrep... /usr/bin/grep -E</span>
<span style="color: #777777;">checking for ANSI C header files... yes</span>
<span style="color: #777777;">checking for sys/types.h... yes</span>
<span style="color: #777777;">checking for sys/stat.h... yes</span>
<span style="color: #777777;">checking for stdlib.h... yes</span>
<span style="color: #777777;">checking for string.h... yes</span>
<span style="color: #777777;">checking for memory.h... yes</span>
<span style="color: #777777;">checking for strings.h... yes</span>
<span style="color: #777777;">checking for inttypes.h... yes</span>
<span style="color: #777777;">checking for stdint.h... yes</span>
<span style="color: #777777;">checking for unistd.h... yes</span>
<span style="color: #777777;">checking stdio.h usability... yes</span>
<span style="color: #777777;">checking stdio.h presence... yes</span>
<span style="color: #777777;">checking for stdio.h... yes</span>
<span style="color: #777777;">checking for stdlib.h... (cached) yes</span>
<span style="color: #777777;">checking for string.h... (cached) yes</span>
<span style="color: #777777;">checking for unistd.h... (cached) yes</span>
<span style="color: #777777;">checking fcntl.h usability... yes</span>
<span style="color: #777777;">checking fcntl.h presence... yes</span>
<span style="color: #777777;">checking for fcntl.h... yes</span>
<span style="color: #777777;">checking errno.h usability... yes</span>
<span style="color: #777777;">checking errno.h presence... yes</span>
<span style="color: #777777;">checking for errno.h... yes</span>
<span style="color: #777777;">checking getopt.h usability... yes</span>
<span style="color: #777777;">checking getopt.h presence... yes</span>
<span style="color: #777777;">checking for getopt.h... yes</span>
<span style="color: #777777;">checking for sys/types.h... (cached) yes</span>
<span style="color: #777777;">checking for sys/stat.h... (cached) yes</span>
<span style="color: #777777;">checking sys/ioctl.h usability... yes</span>
<span style="color: #777777;">checking sys/ioctl.h presence... yes</span>
<span style="color: #777777;">checking for sys/ioctl.h... yes</span>
<span style="color: #777777;">checking linux/i2c.h usability... yes</span>
<span style="color: #777777;">checking linux/i2c.h presence... yes</span>
<span style="color: #777777;">checking for linux/i2c.h... yes</span>
<span style="color: #777777;">checking linux/i2c-dev.h usability... yes</span>
<span style="color: #777777;">checking linux/i2c-dev.h presence... yes</span>
<span style="color: #777777;">checking for linux/i2c-dev.h... yes</span>
<span style="color: #777777;">checking for size_t... yes</span>
<span style="color: #777777;">checking that generated files are newer than configure... done</span>
<span style="color: #777777;">configure: creating ./config.status</span>
<span style="color: #777777;">config.status: creating Makefile</span>
<span style="color: #777777;">config.status: creating cfg/Makefile</span>
<span style="color: #777777;">config.status: creating src/Makefile</span>
<span style="color: #777777;">config.status: creating cfg/config.h</span>
<span style="color: #777777;">config.status: executing depfiles commands</span>
<span style="color: #348c00;">$ esdk></span> make
<span style="color: #777777;">Making all in src</span>
<span style="color: #777777;">make[1]: Entering directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build/src'</span>
<span style="color: #777777;">make[2]: Entering directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build/src'</span>
<span style="color: #777777;">gcc -DHAVE_CONFIG_H -I. -I../../src -I../cfg -Wall -Werror -Wextra -Wconversion -Wreturn-type -Wstrict-prototypes -g -O2 -MT i2ctest.o -MD -MP -MF .deps/i2ctest.Tpo -c -o i2ctest.o ../../src/i2ctest.c</span>
<span style="color: #777777;">mv -f .deps/i2ctest.Tpo .deps/i2ctest.Po</span>
<span style="color: #777777;">gcc -Wall -Werror -Wextra -Wconversion -Wreturn-type -Wstrict-prototypes -g -O2 -o i2ctest i2ctest.o </span>
<span style="color: #777777;">make[2]: Leaving directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build/src'</span>
<span style="color: #777777;">make[1]: Leaving directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build/src'</span>
<span style="color: #777777;">make[1]: Entering directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build'</span>
<span style="color: #777777;">make[1]: Nothing to be done for 'all-am'.</span>
<span style="color: #777777;">make[1]: Leaving directory '/opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles/_build'</span>
<span style="color: #348c00;">$ esdk></span> file src/i2ctest
<span style="color: #777777;">src/i2ctest: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, BuildID[sha1]=4199ed513fc41043d24d05b43075b73fc9037e87, for GNU/Linux 3.2.0, with debug_info, not stripped</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">However, note that in order to take full advantage of <i>devtool</i> (e.g. <i>devtool deploy-target</i>) the independent developer needs to create a recipe for the code they're writing:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$ esdk></span> devtool add automationhat-doodles /opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Recipe /opt/toolchains/automation-hat/poky/esdk/workspace/recipes/automationhat-doodles/automationhat-doodles_0.1.0.bb has been automatically created; further editing may be required to make it fully functional</span>
<span style="color: #348c00;">$ esdk></span> devtool build automationhat-doodles
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% |#################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 3213 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |###############################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2043 .bb files complete (2042 cached, 1 parsed). 3214 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">Loading cache: 100% |#################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Loaded 3213 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |###############################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2043 .bb files complete (2042 cached, 1 parsed). 3214 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Initialising tasks: 100% |############################################################| Time: 0:00:00</span>
<span style="color: #777777;">Sstate summary: Wanted 8 Found 1 Missed 7 Current 108 (12% match, 93% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: automationhat-doodles: compiling from external source tree /opt/oe/configs/z/build-master/6951/automation-hat/devel/automationhat-doodles</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 495 tasks of which 487 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Build completion summary:</span>
<span style="color: #777777;">NOTE: do_populate_sysroot: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_deploy_source_date_epoch: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_package: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_packagedata: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #348c00;">$ esdk></span> devtool deploy-target automationhat-doodles root@10.0.0.50
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% |#################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 3213 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |###############################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2043 .bb files complete (2042 cached, 1 parsed). 3214 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">tar: ./usr/bin/i2ctest: time stamp 2020-10-18 18:16:41 is 82401236.305274304 s in the future</span>
<span style="color: #777777;">tar: ./usr/bin: time stamp 2020-10-18 18:16:41 is 82401236.304915762 s in the future</span>
<span style="color: #777777;">tar: ./usr: time stamp 2020-10-18 18:16:41 is 82401236.304415189 s in the future</span>
<span style="color: #777777;">tar: .: time stamp 2020-10-18 18:16:41 is 82401236.304187064 s in the future</span>
<span style="color: #777777;">INFO: Successfully deployed /opt/toolchains/automation-hat/poky/esdk/tmp/work/cortexa53-poky-linux/automationhat-doodles/0.1.0-r0/image</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;"><br /></p><h2 style="text-align: left;">Turning On An LED</h2><p style="text-align: left;">We now have the mechanics in place for writing, cross-compiling, and on-device testing of your code as it is being written, all using the same bleeding-edge, state-of-the-art tools being used to build your image.</p><p style="text-align: left;">Working through the code to get an LED lit we end up with:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;">/*</span>
<span style="color: #777777; font-style: italic;"> * Copyright (C) 2020 Trevor Woerner <twoerner@gmail.com></span>
<span style="color: #777777; font-style: italic;"> */</span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;">"config.h"</span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><stdio.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><stdlib.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><string.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><unistd.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><fcntl.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><sys/types.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><sys/stat.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><sys/ioctl.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><i2c/smbus.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><linux/i2c.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><linux/i2c-dev.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #cd2828; font-weight: bold;">#include</span> <span style="color: #777777; font-style: italic;"><getopt.h></span><span style="color: #cd2828; font-weight: bold;"></span>
<span style="color: #6ab825; font-weight: bold;">static</span> <span style="color: #6ab825; font-weight: bold;">char</span> *i2cDevice_pG = <span style="color: #bf7f0f;">"/dev/i2c-1"</span>;
<span style="color: #6ab825; font-weight: bold;">static</span> <span style="color: #6ab825; font-weight: bold;">void</span> <span style="color: #447fcf;">print_funcs</span>(<span style="color: #6ab825; font-weight: bold;">unsigned</span> <span style="color: #6ab825; font-weight: bold;">long</span>);
<span style="color: #6ab825; font-weight: bold;">static</span> <span style="color: #6ab825; font-weight: bold;">void</span> <span style="color: #447fcf;">process_cmdline_args</span>(<span style="color: #6ab825; font-weight: bold;">int</span>,<span style="color: #6ab825; font-weight: bold;">char</span>**);
<span style="color: #6ab825; font-weight: bold;">static</span> <span style="color: #6ab825; font-weight: bold;">void</span> <span style="color: #447fcf;">usage</span>(<span style="color: #6ab825; font-weight: bold;">const</span> <span style="color: #6ab825; font-weight: bold;">char</span>*);
<span style="color: #6ab825; font-weight: bold;">int</span>
<span style="color: #447fcf;">main</span> (<span style="color: #6ab825; font-weight: bold;">int</span> argc, <span style="color: #6ab825; font-weight: bold;">char</span> *argv[])
{
<span style="color: #6ab825; font-weight: bold;">int</span> ret;
<span style="color: #6ab825; font-weight: bold;">int</span> i2cFd;
<span style="color: #6ab825; font-weight: bold;">unsigned</span> <span style="color: #6ab825; font-weight: bold;">long</span> funcs;
<span style="color: #777777; font-style: italic;">/* process cmdline - get i2c device */</span>
process_cmdline_args(argc, argv);
<span style="color: #6ab825; font-weight: bold;">if</span> (optind == argc)
;
<span style="color: #6ab825; font-weight: bold;">else</span> <span style="color: #6ab825; font-weight: bold;">if</span> ((optind+<span style="color: #3677a9;">1</span>) == argc) {
i2cDevice_pG = strdup(argv[optind]);
<span style="color: #6ab825; font-weight: bold;">if</span> (i2cDevice_pG == NULL) {
perror(<span style="color: #bf7f0f;">"strdup()"</span>);
<span style="color: #6ab825; font-weight: bold;">return</span> <span style="color: #3677a9;">1</span>;
}
}
<span style="color: #6ab825; font-weight: bold;">else</span> {
fprintf(stderr, <span style="color: #bf7f0f;">"bad cmdline args\n"</span>);
usage(argv[<span style="color: #3677a9;">0</span>]);
<span style="color: #6ab825; font-weight: bold;">return</span> <span style="color: #3677a9;">1</span>;
}
printf(<span style="color: #bf7f0f;">"device: %s\n"</span>, i2cDevice_pG);
<span style="color: #777777; font-style: italic;">/* open i2c device */</span>
i2cFd = open(i2cDevice_pG, O_RDWR);
<span style="color: #6ab825; font-weight: bold;">if</span> (i2cFd < <span style="color: #3677a9;">0</span>) {
perror(<span style="color: #bf7f0f;">"open()"</span>);
<span style="color: #6ab825; font-weight: bold;">return</span> <span style="color: #3677a9;">1</span>;
}
<span style="color: #777777; font-style: italic;">/* figure out and show i2c capabilities */</span>
ret = ioctl(i2cFd, I2C_FUNCS, &funcs);
<span style="color: #6ab825; font-weight: bold;">if</span> (ret < <span style="color: #3677a9;">0</span>) {
perror(<span style="color: #bf7f0f;">"ioctl()"</span>);
close(i2cFd);
<span style="color: #6ab825; font-weight: bold;">return</span> <span style="color: #3677a9;">1</span>;
}
printf(<span style="color: #bf7f0f;">"funcs: 0x%08lx\n"</span>, funcs);
print_funcs(funcs);
<span style="color: #777777; font-style: italic;">/* interract with device */</span>
ret = ioctl(i2cFd, I2C_SLAVE, <span style="color: #3677a9;">0x54</span>);
<span style="color: #6ab825; font-weight: bold;">if</span> (ret < <span style="color: #3677a9;">0</span>) {
perror(<span style="color: #bf7f0f;">"I2C_SLAVE"</span>);
<span style="color: #6ab825; font-weight: bold;">return</span> <span style="color: #3677a9;">1</span>;
}
i2c_smbus_write_byte_data(i2cFd, <span style="color: #3677a9;">0x17</span>, <span style="color: #3677a9;">0xff</span>); <span style="color: #777777; font-style: italic;">// reset</span>
i2c_smbus_write_byte_data(i2cFd, <span style="color: #3677a9;">0x00</span>, <span style="color: #3677a9;">0x01</span>); <span style="color: #777777; font-style: italic;">// enable</span>
i2c_smbus_write_byte_data(i2cFd, <span style="color: #3677a9;">0x12</span>, <span style="color: #3677a9;">0x10</span>); <span style="color: #777777; font-style: italic;">// some pwm on channel 0x12</span>
i2c_smbus_write_byte_data(i2cFd, <span style="color: #3677a9;">0x15</span>, <span style="color: #3677a9;">0x20</span>); <span style="color: #777777; font-style: italic;">// turn on channel 0x12</span>
i2c_smbus_write_byte_data(i2cFd, <span style="color: #3677a9;">0x16</span>, <span style="color: #3677a9;">0xff</span>); <span style="color: #777777; font-style: italic;">// update</span>
close(i2cFd);
<span style="color: #6ab825; font-weight: bold;">return</span> <span style="color: #3677a9;">0</span>;
}
<span style="color: #6ab825; font-weight: bold;">static</span> <span style="color: #6ab825; font-weight: bold;">struct</span> {
<span style="color: #6ab825; font-weight: bold;">unsigned</span> <span style="color: #6ab825; font-weight: bold;">long</span> flag;
<span style="color: #6ab825; font-weight: bold;">const</span> <span style="color: #6ab825; font-weight: bold;">char</span> *str_p;
} I2CFlags_G[] = {
{I2C_FUNC_I2C, <span style="color: #bf7f0f;">"I2C_FUNC_I2C"</span>},
{I2C_FUNC_10BIT_ADDR, <span style="color: #bf7f0f;">"I2C_FUNC_10BIT_ADDR"</span>},
{I2C_FUNC_PROTOCOL_MANGLING, <span style="color: #bf7f0f;">"I2C_FUNC_PROTOCOL_MANGLING"</span>},
{I2C_FUNC_SMBUS_PEC, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_PEC"</span>},
{I2C_FUNC_NOSTART, <span style="color: #bf7f0f;">"I2C_FUNC_NOSTART"</span>},
{I2C_FUNC_SLAVE, <span style="color: #bf7f0f;">"I2C_FUNC_SLAVE"</span>},
{I2C_FUNC_SMBUS_BLOCK_PROC_CALL, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_BLOCK_PROC_CALL"</span>},
{I2C_FUNC_SMBUS_QUICK, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_QUICK"</span>},
{I2C_FUNC_SMBUS_READ_BYTE, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_READ_BYTE"</span>},
{I2C_FUNC_SMBUS_WRITE_BYTE, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_WRITE_BYTE"</span>},
{I2C_FUNC_SMBUS_READ_BYTE_DATA, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_READ_BYTE_DATA"</span>},
{I2C_FUNC_SMBUS_WRITE_BYTE_DATA, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_WRITE_BYTE_DATA"</span>},
{I2C_FUNC_SMBUS_READ_WORD_DATA, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_READ_WORD_DATA"</span>},
{I2C_FUNC_SMBUS_WRITE_WORD_DATA, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_WRITE_WORD_DATA"</span>},
{I2C_FUNC_SMBUS_PROC_CALL, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_PROC_CALL"</span>},
{I2C_FUNC_SMBUS_READ_BLOCK_DATA, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_READ_BLOCK_DATA"</span>},
{I2C_FUNC_SMBUS_WRITE_BLOCK_DATA, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_WRITE_BLOCK_DATA"</span>},
{I2C_FUNC_SMBUS_READ_I2C_BLOCK, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_READ_I2C_BLOCK"</span>},
{I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_WRITE_I2C_BLOCK"</span>},
{I2C_FUNC_SMBUS_HOST_NOTIFY, <span style="color: #bf7f0f;">"I2C_FUNC_SMBUS_HOST_NOTIFY"</span>},
};
<span style="color: #cd2828; font-weight: bold;">#define I2CFLAGS_SZ (sizeof(I2CFlags_G) / sizeof(I2CFlags_G[0]))</span>
<span style="color: #6ab825; font-weight: bold;">static</span> <span style="color: #6ab825; font-weight: bold;">void</span>
<span style="color: #447fcf;">print_funcs</span> (<span style="color: #6ab825; font-weight: bold;">unsigned</span> <span style="color: #6ab825; font-weight: bold;">long</span> funcs)
{
<span style="color: #6ab825; font-weight: bold;">size_t</span> i;
<span style="color: #6ab825; font-weight: bold;">for</span> (i=<span style="color: #3677a9;">0</span>; i<I2CFLAGS_SZ; ++i)
<span style="color: #6ab825; font-weight: bold;">if</span> (funcs & I2CFlags_G[i].flag)
printf(<span style="color: #bf7f0f;">"- %s\n"</span>, I2CFlags_G[i].str_p);
}
<span style="color: #6ab825; font-weight: bold;">static</span> <span style="color: #6ab825; font-weight: bold;">void</span>
<span style="color: #447fcf;">usage</span> (<span style="color: #6ab825; font-weight: bold;">const</span> <span style="color: #6ab825; font-weight: bold;">char</span> *pgm_p)
{
fprintf(stderr, <span style="color: #bf7f0f;">"%s\n"</span>, PACKAGE_STRING);
<span style="color: #6ab825; font-weight: bold;">if</span> (pgm_p != NULL)
fprintf(stderr, <span style="color: #bf7f0f;">"\nusage: %s [opts] [device]\n"</span>, pgm_p);
fprintf(stderr, <span style="color: #bf7f0f;">" where [device]:\n"</span>);
fprintf(stderr, <span style="color: #bf7f0f;">" optionally provide the i2c device node to use\n"</span>);
fprintf(stderr, <span style="color: #bf7f0f;">" (default: %s)\n"</span>, i2cDevice_pG);
fprintf(stderr, <span style="color: #bf7f0f;">" where [opts]:\n"</span>);
fprintf(stderr, <span style="color: #bf7f0f;">" -h|--help print this help and exit successfully\n"</span>);
}
<span style="color: #6ab825; font-weight: bold;">static</span> <span style="color: #6ab825; font-weight: bold;">void</span>
<span style="color: #447fcf;">process_cmdline_args</span> (<span style="color: #6ab825; font-weight: bold;">int</span> argc, <span style="color: #6ab825; font-weight: bold;">char</span> *argv[])
{
<span style="color: #6ab825; font-weight: bold;">int</span> c;
<span style="color: #6ab825; font-weight: bold;">struct</span> option longOpts[] = {
{<span style="color: #bf7f0f;">"help"</span>, no_argument, NULL, <span style="color: #bf7f0f;">'h'</span>},
{NULL, <span style="color: #3677a9;">0</span>, NULL, <span style="color: #3677a9;">0</span>},
};
<span style="color: #6ab825; font-weight: bold;">while</span> (<span style="color: #3677a9;">1</span>) {
c = getopt_long(argc, argv, <span style="color: #bf7f0f;">"h"</span>, longOpts, NULL);
<span style="color: #6ab825; font-weight: bold;">if</span> (c == -<span style="color: #3677a9;">1</span>)
<span style="color: #6ab825; font-weight: bold;">break</span>;
<span style="color: #6ab825; font-weight: bold;">switch</span> (c) {
<span style="color: #6ab825; font-weight: bold;">case</span> <span style="color: #bf7f0f;">'h'</span>:
usage(argv[<span style="color: #3677a9;">0</span>]);
exit(<span style="color: #3677a9;">0</span>);
<span style="color: #6ab825; font-weight: bold;">break</span>;
<span style="color: #6ab825; font-weight: bold;">default</span>:
fprintf(stderr, <span style="color: #bf7f0f;">"unknown getopt: %d (0x%02x)\n"</span>, c, c);
<span style="color: #6ab825; font-weight: bold;">break</span>;
}
}
}
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">This C code for i2c has a dependency on i2c-tools, so the following updates are required.</p><p style="text-align: left;"><span style="font-family: courier; font-size: x-small;">configure.ac</span>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;">dnl Copyright (C) 2020 Trevor Woerner <twoerner@gmail.com></span>
AC_PREREQ(2.57)
AC_INIT([automationhat-doodles], 0.1.0, twoerner@gmail.com, automationhat-doodles)
AC_CONFIG_SRCDIR(src/i2ctest.c)
AC_CONFIG_AUX_DIR(cfg)
AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-bzip2 1.9])
AM_CONFIG_HEADER(cfg/config.h)
SUBDIRS="src"
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl checks for programs</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_PROG_CC
AC_PROG_CPP
AC_PROG_MAKE_SET
AC_PROG_INSTALL
AC_PROG_LN_S
<span style="color: #6ab825; font-weight: bold;">dnl **********************************</span>
<span style="color: #6ab825; font-weight: bold;">dnl checks for libraries</span>
<span style="color: #6ab825; font-weight: bold;">dnl **********************************</span>
<span style="color: #6ab825; font-weight: bold;">AC_CHECK_LIB(i2c, i2c_smbus_write_block_data, ,AC_MSG_ERROR([Can't find library i2c]), )</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl checks for header files</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_HEADER_STDC
AC_CHECK_HEADERS(stdio.h stdlib.h string.h unistd.h fcntl.h errno.h getopt.h)
AC_CHECK_HEADERS(sys/types.h sys/stat.h sys/ioctl.h linux/i2c.h linux/i2c-dev.h)
<span style="color: #6ab825; font-weight: bold;">AC_CHECK_HEADERS(i2c/smbus.h)</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl checks for typedefs, structs, and</span>
<span style="color: #777777; font-style: italic;">dnl compiler characteristics</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_TYPE_SIZE_T
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl other stuff</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_SUBST(SUBDIRS)
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
<span style="color: #777777; font-style: italic;">dnl output</span>
<span style="color: #777777; font-style: italic;">dnl **********************************</span>
AC_OUTPUT(Makefile
cfg/Makefile
src/Makefile)
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">and modify the <span style="font-family: courier; font-size: x-small;">automationhat-doodles</span> recipe:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;"># Recipe created by recipetool</span>
<span style="color: #777777; font-style: italic;"># This is the basis of a recipe and may need further editing in order to be fully functional.</span>
<span style="color: #777777; font-style: italic;"># (Feel free to remove these comments when editing.)</span>
<span style="color: #777777; font-style: italic;"># Unable to find any files that looked like license statements. Check the accompanying</span>
<span style="color: #777777; font-style: italic;"># documentation and source headers and set LICENSE and LIC_FILES_CHKSUM accordingly.</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #777777; font-style: italic;"># NOTE: LICENSE is being set to "CLOSED" to allow you to at least start building - if</span>
<span style="color: #777777; font-style: italic;"># this is not accurate with respect to the licensing of the software being built (it</span>
<span style="color: #777777; font-style: italic;"># will not be in most cases) you must specify the correct value before using this</span>
<span style="color: #777777; font-style: italic;"># recipe for anything other than initial testing/development!</span>
LICENSE = "CLOSED"
LIC_FILES_CHKSUM = ""
<span style="color: #777777; font-style: italic;"># No information for SRC_URI yet (only an external source tree was specified)</span>
SRC_URI = ""
<span style="color: #777777; font-style: italic;"># NOTE: if this software is not capable of being built in a separate build directory</span>
<span style="color: #777777; font-style: italic;"># from the source, you should replace autotools with autotools-brokensep in the</span>
<span style="color: #777777; font-style: italic;"># inherit line</span>
inherit autotools
<span style="color: #777777; font-style: italic;"># Specify any options you want to pass to the configure script using EXTRA_OECONF:</span>
EXTRA_OECONF = ""
<span style="color: #6ab825; font-weight: bold;">DEPENDS += "i2c-tools"</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Running the code on the target:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@raspberrypi3-64:~#</span> i2ctest
<span style="color: #777777;">device: /dev/i2c-1</span>
<span style="color: #777777;">funcs: 0x0eff0009</span>
<span style="color: #777777;">- I2C_FUNC_I2C</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_PEC</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_QUICK</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_READ_BYTE</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_WRITE_BYTE</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_READ_BYTE_DATA</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_WRITE_BYTE_DATA</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_READ_WORD_DATA</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_WRITE_WORD_DATA</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_PROC_CALL</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_WRITE_BLOCK_DATA</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_READ_I2C_BLOCK</span>
<span style="color: #777777;">- I2C_FUNC_SMBUS_WRITE_I2C_BLOCK</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">and looking at the target:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-bo-BSnMNExo/X40X3HPb15I/AAAAAAAAiyA/FggOkRmgUZU5pzoP6Rab-BUdyOqWsvlfQCLcBGAsYHQ/s640/IMG_4150.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" src="https://1.bp.blogspot.com/-bo-BSnMNExo/X40X3HPb15I/AAAAAAAAiyA/FggOkRmgUZU5pzoP6Rab-BUdyOqWsvlfQCLcBGAsYHQ/s320/IMG_4150.JPG" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-IP9Cr08u8L0/X40YKwzuy7I/AAAAAAAAiyY/cZ-e8yfR0OwYySrHnDLhzXPRDpH-ggdMgCLcBGAsYHQ/s640/IMG_4149.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" src="https://1.bp.blogspot.com/-IP9Cr08u8L0/X40YKwzuy7I/AAAAAAAAiyY/cZ-e8yfR0OwYySrHnDLhzXPRDpH-ggdMgCLcBGAsYHQ/s320/IMG_4149.JPG" width="320" /></a></div>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-78659673479073424142020-10-05T19:40:00.351-04:002022-03-21T08:43:37.148-04:00Pimoroni Automation-HAT Meets OpenEmbedded<h2 style="text-align: left;">Preamble</h2>
<p>I found <a href="https://shop.pimoroni.com/products/automation-hat" target="_blank">this</a> device, the Automation-HAT by Pimoroni, which I thought might be fun for some HVAC experimenting I'd like to explore in the future. The creators of this Automation-HAT even provide a <a href="https://github.com/pimoroni/automation-hat" target="_blank">python library</a>. Since I'm a fan of Yocto/OpenEmbedded (OE) I wanted to explore the steps in getting the Automation-HAT working with my own image instead of using, say, <a href="https://www.raspberrypi.org/downloads/raspberry-pi-os/" target="_blank">Raspberry Pi OS</a>.</p>
<h2 style="text-align: left;">Master or Release?</h2>
<p style="text-align: left;">Choosing between using master or basing on a release isn't easy when writing a blog post. On the one hand using a release can often be "safer", meaning a person stumbling into this post might have a greater chance of following along if everything is based on a "stable" release. But in my experience all software ages badly in blog posts, and working off of master is more fun for me. So master it is!</p>
<h2 style="text-align: left;">Getting Setup and First Build</h2>
<p style="text-align: left;">There are lots of "Getting Started" guides for working with The Yocto Project or OpenEmbedded so if the following instructions skip too many steps, feel free to work through some of those other resources in order to get going.</p>
<p style="text-align: left;">Whenever I work on a technical project, I've always liked the approach of getting <i>something</i> working, and building from there. As such my first goal is to get a very basic image building and working on the device. Then we can start adding to what we know works, in order to build up to our goal.</p>
<p style="text-align: left;">For this Yocto build I'm going to start with <span style="font-family: courier; font-size: x-small;">poky</span>. Since I'll be attaching this device to a Raspberry Pi (a Raspberry Pi 3, to be exact) I'll also need the OE BSP layer for that hardware. Create a fresh directory somewhere on your system to work and:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> mkdir layers
<span style="color: #348c00;">$</span> pushd layers
<span style="color: #348c00;">$</span> git clone git://git.yoctoproject.org/poky
<span style="color: #348c00;">$</span> git clone git://git.yoctoproject.org/meta-raspberrypi.git
<span style="color: #348c00;">$</span> popd
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">In my specific case the HEADs of these repositories are set at:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span style="color: #777777;">poky: 7cad26d585f67fa6bf873b8be361c6335a7db376</span>
<span style="color: #777777;">meta-raspberrypi: 6f85611576b7ccbfb6012631f741bd1daeffc9c9</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Initialize your shell environment to get ready to build:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> . layers/poky/oe-init-build-env
<span style="color: #777777;">You had no conf/local.conf file. This configuration file has therefore been</span>
<span style="color: #777777;">created for you with some default values. You may wish to edit it to, for</span>
<span style="color: #777777;">example, select a different MACHINE (target hardware). See conf/local.conf</span>
<span style="color: #777777;">for more information as common configuration options are commented.</span>
<span style="color: #777777;">You had no conf/bblayers.conf file. This configuration file has therefore been</span>
<span style="color: #777777;">created for you with some default values. To add additional metadata layers</span>
<span style="color: #777777;">into your configuration please add entries to conf/bblayers.conf.</span>
<span style="color: #777777;">The Yocto Project has extensive documentation about OE including a reference</span>
<span style="color: #777777;">manual which can be found at:</span>
<span style="color: #777777;"> http://yoctoproject.org/documentation</span>
<span style="color: #777777;">For more information about OpenEmbedded see their website:</span>
<span style="color: #777777;"> http://www.openembedded.org/</span>
<span style="color: #777777;">### Shell environment set up for builds. ###</span>
<span style="color: #777777;">You can now run 'bitbake <target>'</span>
<span style="color: #777777;">Common targets are:</span>
<span style="color: #777777;"> core-image-minimal</span>
<span style="color: #777777;"> core-image-sato</span>
<span style="color: #777777;"> meta-toolchain</span>
<span style="color: #777777;"> meta-ide-support</span>
<span style="color: #777777;">You can also run generated qemu images with a command like 'runqemu qemux86'</span>
<span style="color: #777777;">Other commonly useful commands are:</span>
<span style="color: #777777;"> - 'devtool' and 'recipetool' handle common recipe tasks</span>
<span style="color: #777777;"> - 'bitbake-layers' handles common layer tasks</span>
<span style="color: #777777;"> - 'oe-pkgdata-util' handles common target package tasks</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Make your build aware of the BSP layer:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake-layers add-layer ../layers/meta-raspberrypi/
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">When you initialized your shell earlier, it created a basic <span style="font-family: courier; font-size: x-small;">conf/local.conf</span> template for you. You need to edit this file. The basic config file is filled with comments that can be quite useful. Stripping out the comments and adding/tweaking the build for my purposes I ended up with the following:</p><p style="text-align: left;"></p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">MACHINE</span> = <span style="color: #bf7f0f;">"raspberrypi3-64"</span>
<span style="color: #2db5b5;">DL_DIR</span> = <span style="color: #bf7f0f;">"/opt/Downloads"</span>
<span style="color: #2db5b5;">DISTRO</span> = <span style="color: #bf7f0f;">"poky"</span>
<span style="color: #2db5b5;">CORE_IMAGE_EXTRA_INSTALL</span> += <span style="color: #bf7f0f;">" \</span>
<span style="color: #bf7f0f;"> </span><span style="color: #777777; font-style: italic;">${MACHINE_EXTRA_RRECOMMENDS}</span><span style="color: #bf7f0f;"> \</span>
<span style="color: #bf7f0f;"> wpa-supplicant \</span>
<span style="color: #bf7f0f;"> "</span>
<span style="color: #2db5b5;">PACKAGECONFIG_append_pn-gdb</span> = <span style="color: #bf7f0f;">" tui"</span>
<span style="color: #2db5b5;">PACKAGECONFIG_append_pn-gdb-cross-canadian-arm</span> = <span style="color: #bf7f0f;">" tui"</span>
<span style="color: #2db5b5;">IMAGE_FSTYPES_append</span> = <span style="color: #bf7f0f;">" wic"</span>
<span style="color: #2db5b5;">IMAGE_FSTYPES_remove</span> = <span style="color: #bf7f0f;">"wic.bz2 tar.bz2"</span>
<span style="color: #2db5b5;">WARN_QA_append</span> = <span style="color: #bf7f0f;">" version-going-backwards"</span>
<span style="color: #2db5b5;">ERROR_QA_remove</span> = <span style="color: #bf7f0f;">"version-going-backwards"</span>
<span style="color: #2db5b5;">BB_DANGLINGAPPENDS_WARNONLY</span> = <span style="color: #bf7f0f;">"yes"</span>
<span style="color: #2db5b5;">INHERIT</span> += <span style="color: #bf7f0f;">"buildhistory image-buildinfo buildstats-summary"</span>
<span style="color: #2db5b5;">BUILDHISTORY_COMMIT</span> = <span style="color: #bf7f0f;">"1"</span>
<span style="color: #2db5b5;">PACKAGE_CLASSES</span> ?= <span style="color: #bf7f0f;">"package_ipk"</span>
<span style="color: #2db5b5;">SDKMACHINE</span> = <span style="color: #bf7f0f;">"x86_64"</span>
<span style="color: #2db5b5;">EXTRA_IMAGE_FEATURES</span> ?= <span style="color: #bf7f0f;">"debug-tweaks"</span>
<span style="color: #2db5b5;">USER_CLASSES</span> ?= <span style="color: #bf7f0f;">"buildstats image-mklibs image-prelink"</span>
<span style="color: #2db5b5;">PATCHRESOLVE</span> = <span style="color: #bf7f0f;">"noop"</span>
<span style="color: #2db5b5;">BB_DISKMON_DIRS</span> ??= <span style="color: #bf7f0f;">"\</span>
<span style="color: #bf7f0f;"> STOPTASKS,</span><span style="color: #777777; font-style: italic;">${TMPDIR}</span><span style="color: #bf7f0f;">,1G,100K \</span>
<span style="color: #bf7f0f;"> STOPTASKS,</span><span style="color: #777777; font-style: italic;">${DL_DIR}</span><span style="color: #bf7f0f;">,1G,100K \</span>
<span style="color: #bf7f0f;"> STOPTASKS,</span><span style="color: #777777; font-style: italic;">${SSTATE_DIR}</span><span style="color: #bf7f0f;">,1G,100K \</span>
<span style="color: #bf7f0f;"> STOPTASKS,/tmp,100M,100K \</span>
<span style="color: #bf7f0f;"> ABORT,</span><span style="color: #777777; font-style: italic;">${TMPDIR}</span><span style="color: #bf7f0f;">,100M,1K \</span>
<span style="color: #bf7f0f;"> ABORT,</span><span style="color: #777777; font-style: italic;">${DL_DIR}</span><span style="color: #bf7f0f;">,100M,1K \</span>
<span style="color: #bf7f0f;"> ABORT,</span><span style="color: #777777; font-style: italic;">${SSTATE_DIR}</span><span style="color: #bf7f0f;">,100M,1K \</span>
<span style="color: #bf7f0f;"> ABORT,/tmp,10M,1K"</span>
<span style="color: #2db5b5;">PACKAGECONFIG_append_pn-qemu-system-native</span> = <span style="color: #bf7f0f;">" sdl"</span>
<span style="color: #2db5b5;">CONF_VERSION</span> = <span style="color: #bf7f0f;">"1"</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;"></p><ul style="text-align: left;"><li>Line 1: The MACHINE is set to "raspberrypi3-64" since that is the target I want from the set of machines that are defined in the meta-raspberrypi BSP.</li><li>Line 2: The DL_DIR points to a folder on my host machine which will be where all downloads for this build will be placed. You'll need to specify a location on your machine to which you have write access and which is large enough to store these downloads.</li><li>Line 3: I've chosen the <i>poky</i> DISTRO.</li><li>Lines 5-8: I want to add a couple things to my image so I include them here (the fact <span style="font-family: courier; font-size: x-small;">MACHINE_EXTRA_RRECOMMENDS</span> isn't getting added by default to <i>core-image-full-cmdline</i>, I believe, is a bug, but we can work around it like this)</li><li>Lines 10-11: Whenever I used gdb I like to use its curses-based GUI mode. Therefore I've set some <span style="font-family: courier; font-size: x-small;">PACKAGECONFIG</span>s to say that whenever gdb is built, please configure it for "tui" mode.</li><li>Line 13: Flashing wic images are much faster than flashing a non-wic image. Therefore I like to configure my µSD card builds to use wic.</li><li>Line 14: Since I'm not transferring these images over a network, or saving them for eternity on a drive somewhere, I don't care for them to be compressed; the compression stage at the end of a build just wastes time for me in this case.</li><li>Lines 15-16: Sometimes when building different revisions of git code, one SHA will be alphanumerically "lower" than a previous (in time) SHA. The build will flag this and error out thinking that you're downgrading a given piece of software. I like to add these lines to my builds to switch this from an error to a warning.</li><li>Line 17: Sometimes a layer includes metadata that appends to a recipe that doesn't exist anywhere in your build. This line switches this situation from an error to a warning.</li><li>Lines 18-19: I like using the buildhistory feature, as well as enabling other build metrics.</li><li>Line 21: I've set the PACKAGE_CLASS to <i>ipk</i> from <i>poky</i>'s default of <i>rpm</i></li><li>Line 22: I've set the SDKMACHINE to <i>x86_64</i></li><li>Lines 23-36: Are taken from the template that is created when the build area is initialized by the oe-init-build-env script.</li></ul><p></p>
<p style="text-align: left;">Now we build:<br />[<i><b>NOTE</b></i>: depending on the characteristics of your host machine and the speed of your connection to the internet, your initial build could take anywhere from 20 minutes to an hour or so]</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake core-image-full-cmdline
<span style="color: #777777;">Loading cache: 100% | | ETA: --:--:--</span>
<span style="color: #777777;">Loaded 0 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:09</span>
<span style="color: #777777;">Parsing of 814 .bb files complete (0 cached, 814 parsed). 1383 targets, 65 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "opensuseleap-15.1"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201017"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:03</span>
<span style="color: #777777;">Sstate summary: Wanted 1522 Found 0 Missed 1522 Current 0 (0% match, 0% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">WARNING: linux-raspberrypi-1_5.4.69+gitAUTOINC+5d52d9eea9_31d364af25-r0 do_kernel_configcheck: [kernel config]: specified values did not make it into the kernel's final configuration:</span>
<span style="color: #777777;"> [NOTE]: 'CONFIG_I2C_BCM2835' last val (m) and .config val (y) do not match</span>
<span style="color: #777777;"> [INFO]: CONFIG_I2C_BCM2835 : y ## .config: 2783 :configs///defconfig (m) </span>
<span style="color: #777777;"> [INFO]: raw config text:</span>
<span style="color: #777777;"> config I2C_BCM2835</span>
<span style="color: #777777;"> tristate "Broadcom BCM2835 I2C controller"</span>
<span style="color: #777777;"> depends on (ARCH_BCM2835 || ARCH_BRCMSTB) && HAS_IOMEM && I2C</span>
<span style="color: #777777;"> help</span>
<span style="color: #777777;"> If you say yes to this option, support will be included for the</span>
<span style="color: #777777;"> BCM2835 I2C controller.</span>
<span style="color: #777777;"> </span>
<span style="color: #777777;"> If you don't know what to do here, say N.</span>
<span style="color: #777777;"> </span>
<span style="color: #777777;"> This support is also available as a module. If so, the module</span>
<span style="color: #777777;"> will be called i2c-bcm2835.</span>
<span style="color: #777777;"> Config 'I2C_BCM2835' has the following Direct dependencies (I2C_BCM2835=y):</span>
<span style="color: #777777;"> ARCH_BCM2835(=y) || ARCH_BRCMSTB(=n) (=y) && HAS_IOMEM(=y) && I2C(=y)</span>
<span style="color: #777777;"> Parent dependencies are:</span>
<span style="color: #777777;"> HAS_IOMEM [y] ARCH_BRCMSTB [n] I2C [y] ARCH_BCM2835 [y]</span>
<span style="color: #777777;"> [NOTE]: 'CONFIG_DRM' last val (m) and .config val (y) do not match</span>
<span style="color: #777777;"> [INFO]: CONFIG_DRM : y ## .config: 4017 :configs///defconfig (m) </span>
<span style="color: #777777;"> [INFO]: raw config text:</span>
<span style="color: #777777;"> menuconfig DRM</span>
<span style="color: #777777;"> tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"</span>
<span style="color: #777777;"> select DRM_PANEL_ORIENTATION_QUIRKS</span>
<span style="color: #777777;"> select HDMI</span>
<span style="color: #777777;"> select FB_CMDLINE</span>
<span style="color: #777777;"> select I2C</span>
<span style="color: #777777;"> select I2C_ALGOBIT</span>
<span style="color: #777777;"> select DMA_SHARED_BUFFER</span>
<span style="color: #777777;"> select SYNC_FILE</span>
<span style="color: #777777;"> depends on (AGP || AGP = n) && !EMULATED_CMPXCHG && HAS_DMA && HAS_IOMEM</span>
<span style="color: #777777;"> help</span>
<span style="color: #777777;"> Kernel-level support for the Direct Rendering Infrastructure (DRI)</span>
<span style="color: #777777;"> introduced in XFree86 4.0. If you say Y here, you need to select</span>
<span style="color: #777777;"> the module that's right for your graphics card from the list below.</span>
<span style="color: #777777;"> These modules provide support for synchronization, security, and</span>
<span style="color: #777777;"> DMA transfers. Please see <http://dri.sourceforge.net/> for more</span>
<span style="color: #777777;"> details. You should also select and configure AGP</span>
<span style="color: #777777;"> (/dev/agpgart) support if it is available for your platform.</span>
<span style="color: #777777;"> Config 'DRM' has the following Direct dependencies (DRM=y):</span>
<span style="color: #777777;"> AGP(=n) || AGP(=n) = n (=y) && !EMULATED_CMPXCHG(undefined/n) (=y) && HAS_DMA(=y) && HAS_IOMEM(=y)</span>
<span style="color: #777777;"> Parent dependencies are:</span>
<span style="color: #777777;"> AGP [n] EMULATED_CMPXCHG [EMULATED_CMPXCHG] HAS_IOMEM [y] HAS_DMA [y]</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 3929 tasks of which 1 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 189 seconds</span>
<span style="color: #777777;">NOTE: Build completion summary:</span>
<span style="color: #777777;">NOTE: do_populate_sysroot: 0.0% sstate reuse(0 setscene, 282 scratch)</span>
<span style="color: #777777;">NOTE: do_deploy_source_date_epoch: 0.0% sstate reuse(0 setscene, 283 scratch)</span>
<span style="color: #777777;">NOTE: do_package_qa: 0.0% sstate reuse(0 setscene, 166 scratch)</span>
<span style="color: #777777;">NOTE: do_package: 0.0% sstate reuse(0 setscene, 166 scratch)</span>
<span style="color: #777777;">NOTE: do_packagedata: 0.0% sstate reuse(0 setscene, 166 scratch)</span>
<span style="color: #777777;">NOTE: do_package_write_ipk: 0.0% sstate reuse(0 setscene, 166 scratch)</span>
<span style="color: #777777;">NOTE: do_populate_lic: 0.0% sstate reuse(0 setscene, 285 scratch)</span>
<span style="color: #777777;">Summary: There was 1 WARNING message shown.</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Now we write the resulting image to a µSD card. As I said earlier, I like to flash a "wic" image whenever possible. But before we can do that, we need to build the wic-flashing tool (bmap) so we can use it to flash the wic image to the µSD card:<br />[<i><b>NOTE</b></i>: this step only ever needs to be done once in a given build area]</p><p style="text-align: left;"></p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake bmap-tools-native -caddto_recipe_sysroot
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 1383 entries from dependency cache.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201017"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Found 0 Missed 0 Current 56 (0% match, 100% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 253 tasks of which 252 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 1 seconds</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Insert the µSD card into your host computer. You'll need to figure out where it appears in your computer so you can specify its location. The method I use is to check the system log. If I've just inserted the device, there will be an entry somewhere at the bottom of the system log indicating the fact a USB device was just inserted and it will specify where it shows up. In my case, when I insert a µSD device into my host via a USB reader, it shows up as <span style="font-family: courier; font-size: x-small;">/dev/sdk</span>. In the examples below you'll have to replace where I write <span style="font-family: courier; font-size: x-small;">/dev/sdk</span> with whatever path is valid for you.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> oe-run-native bmap-tools-native bmaptool copy tmp/deploy/images/raspberrypi3-64/core-image-full-cmdline-raspberrypi3-64.wic /dev/sdk
<span style="color: #777777;">Running bitbake -e bmap-tools-native</span>
<span style="color: #777777;">bmaptool: info: discovered bmap file 'tmp/deploy/images/raspberrypi3-64/core-image-full-cmdline-raspberrypi3-64.wic.bmap'</span>
<span style="color: #777777;">bmaptool: info: block map format version 2.0</span>
<span style="color: #777777;">bmaptool: info: 87962 blocks of size 4096 (343.6 MiB), mapped 50393 blocks (196.8 MiB or 57.3%)</span>
<span style="color: #777777;">bmaptool: info: copying image 'core-image-full-cmdline-raspberrypi3-64.wic' to block device '/dev/sdk' using bmap file 'core-image-full-cmdline-raspberrypi3-64.wic.bmap'</span>
<span style="color: #777777;">bmaptool: WARNING: failed to disable excessive buffering, expect worse system responsiveness (reason: cannot set max. I/O ratio to 1: [Errno 13] Permission denied: '/sys/dev/block/8:160/bdi/max_ratio')</span>
<span style="color: #777777;">bmaptool: info: 100% copied</span>
<span style="color: #777777;">bmaptool: info: synchronizing '/dev/sdk'</span>
<span style="color: #777777;">bmaptool: info: copying time: 22.6s, copying speed 8.7 MiB/sec</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Turning to the target device (i.e. the raspberrypi3) we fit the Automation-HAT to the Pi, wire up the serial console cable, and insert the µSD card.</p><p style="text-align: left;">Here are some pics of my setup:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-8ENyguYX58M/X3pbJuybQ2I/AAAAAAAAiYM/leWIxlO8A8ct7Mk0L7zr-w70ROfMqDYXACLcBGAsYHQ/s640/IMG_4134.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" src="https://1.bp.blogspot.com/-8ENyguYX58M/X3pbJuybQ2I/AAAAAAAAiYM/leWIxlO8A8ct7Mk0L7zr-w70ROfMqDYXACLcBGAsYHQ/s320/IMG_4134.JPG" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-2aXkN0s4ST0/X3pbJYLVc2I/AAAAAAAAiYI/wFar3yWa21UpAduE7E7y-zcyBtXxhkF8ACLcBGAsYHQ/s640/IMG_4135.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" src="https://1.bp.blogspot.com/-2aXkN0s4ST0/X3pbJYLVc2I/AAAAAAAAiYI/wFar3yWa21UpAduE7E7y-zcyBtXxhkF8ACLcBGAsYHQ/s320/IMG_4135.JPG" width="320" /></a></div><br /><p style="text-align: left;"><br /></p><p style="text-align: left;">On the host we watch the system log (again) to see where the serial console cable shows up (e.g. <span style="font-family: courier; font-size: x-small;">/dev/ttyUSB0</span>) and start a terminal on that device (e.g. using <span style="font-family: courier; font-size: x-small;">screen</span>, <span style="font-family: courier; font-size: x-small;">minicom</span>, etc). Now we apply power to the target and… nothing.</p><p style="text-align: left;">As it turns out, we have to explicitly tell the raspberrypi that we want a serial console. This gets configured in the <span style="font-family: courier; font-size: x-small;">conf/local.conf</span> as follows:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DL_DIR = "/opt/Downloads"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #2db5b5;">ENABLE_UART</span> = <span style="color: #bf7f0f;">"1"</span>
<span style="color: #777777;">CORE_IMAGE_EXTRA_INSTALL += " \</span>
<span style="color: #777777;"> ${MACHINE_EXTRA_RRECOMMENDS} \</span>
<span style="color: #777777;"> wpa-supplicant \</span>
<span style="color: #777777;"> "</span>
<span style="color: #777777;">PACKAGECONFIG_append_pn-gdb = " tui"</span>
<span style="color: #777777;">PACKAGECONFIG_append_pn-gdb-cross-canadian-arm = " tui"</span>
<span style="color: #777777;">IMAGE_FSTYPES_append = " wic"</span>
<span style="color: #777777;">IMAGE_FSTYPES_remove = "wic.bz2 tar.bz2"</span>
<span style="color: #777777;">WARN_QA_append = " version-going-backwards"</span>
<span style="color: #777777;">ERROR_QA_remove = "version-going-backwards"</span>
<span style="color: #777777;">BB_DANGLINGAPPENDS_WARNONLY = "yes"</span>
<span style="color: #777777;">INHERIT += "buildhistory image-buildinfo buildstats-summary"</span>
<span style="color: #777777;">BUILDHISTORY_COMMIT = "1"</span>
<span style="color: #777777;">PACKAGE_CLASSES ?= "package_ipk"</span>
<span style="color: #777777;">SDKMACHINE = "x86_64"</span>
<span style="color: #777777;">EXTRA_IMAGE_FEATURES ?= "debug-tweaks"</span>
<span style="color: #777777;">USER_CLASSES ?= "buildstats image-mklibs image-prelink"</span>
<span style="color: #777777;">PATCHRESOLVE = "noop"</span>
<span style="color: #777777;">BB_DISKMON_DIRS ??= "\</span>
<span style="color: #777777;"> STOPTASKS,${TMPDIR},1G,100K \</span>
<span style="color: #777777;"> STOPTASKS,${DL_DIR},1G,100K \</span>
<span style="color: #777777;"> STOPTASKS,${SSTATE_DIR},1G,100K \</span>
<span style="color: #777777;"> STOPTASKS,/tmp,100M,100K \</span>
<span style="color: #777777;"> ABORT,${TMPDIR},100M,1K \</span>
<span style="color: #777777;"> ABORT,${DL_DIR},100M,1K \</span>
<span style="color: #777777;"> ABORT,${SSTATE_DIR},100M,1K \</span>
<span style="color: #777777;"> ABORT,/tmp,10M,1K"</span>
<span style="color: #777777;">PACKAGECONFIG_append_pn-qemu-system-native = " sdl"</span>
<span style="color: #777777;">CONF_VERSION = "1"</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Edit your <span style="font-family: courier; font-size: x-small;">conf/local.conf</span>, rebuild the image, re-flash the image to your µSD card, insert the µSD card into the target, apply power and…</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">[ 0.000000] Machine model: Raspberry Pi 3 Model B Rev 1.2</span>
<span style="color: #777777;">[ 0.000000] efi: Getting EFI parameters from FDT:</span>
<span style="color: #777777;">[ 0.000000] efi: UEFI not found.</span>
<span style="color: #777777;">[ 0.000000] Reserved memory: created CMA memory pool at 0x000000001ec00000, size 256 MiB</span>
<span style="color: #777777;">[ 0.000000] OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool</span>
<span style="color: #777777;">[ 0.000000] percpu: Embedded 31 pages/cpu s88024 r8192 d30760 u126976</span>
<span style="color: #777777;">[ 0.000000] Detected VIPT I-cache on CPU0</span>
<span style="color: #777777;">[ 0.000000] CPU features: detected: ARM erratum 845719</span>
<span style="color: #777777;">[ 0.000000] CPU features: kernel page table isolation forced ON by KASLR</span>
<span style="color: #777777;">[ 0.000000] CPU features: detected: Kernel page table isolation (KPTI)</span>
<span style="color: #777777;">[ 0.000000] CPU features: detected: ARM erratum 843419</span>
<span style="color: #777777;">[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 238896</span>
<span style="color: #777777;">[ 0.000000] Kernel command line: coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1 snd_bcm2835.enable_headphones=1 video=Composite-1:720x480@60i vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000 dwc_otg.lpm_enable=0 console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstyt</span>
<span style="color: #777777;">[ 0.000000] Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes, linear)</span>
<span style="color: #777777;">[ 0.000000] Inode-cache hash table entries: 65536 (order: 7, 524288 bytes, linear)</span>
<span style="color: #777777;">[ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off</span>
<span style="color: #777777;">[ 0.000000] Memory: 669904K/970752K available (9724K kernel code, 1048K rwdata, 3320K rodata, 3072K init, 954K bss, 38704K reserved, 262144K cma-reserved)</span>
<span style="color: #777777;">[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1</span>
<span style="color: #777777;">[ 0.000000] ftrace: allocating 30859 entries in 121 pages</span>
<span style="color: #777777;">[ 0.000000] rcu: Preemptible hierarchical RCU implementation.</span>
<span style="color: #777777;">[ 0.000000] Tasks RCU enabled.</span>
<span style="color: #777777;">[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 100 jiffies.</span>
<span style="color: #777777;">[ 0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0</span>
<span style="color: #777777;">[ 0.000000] random: get_random_bytes called from start_kernel+0x334/0x4c4 with crng_init=0</span>
<span style="color: #777777;">[ 0.000000] arch_timer: cp15 timer(s) running at 19.20MHz (phys).</span>
<span style="color: #777777;">[ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x46d987e47, max_idle_ns: 440795202767 ns</span>
<span style="color: #777777;">[ 0.000007] sched_clock: 56 bits at 19MHz, resolution 52ns, wraps every 4398046511078ns</span>
<span style="color: #777777;">[ 0.000254] Console: colour dummy device 80x25</span>
<span style="color: #777777;">[ 0.000323] Calibrating delay loop (skipped), value calculated using timer frequency.. 38.40 BogoMIPS (lpj=19200)</span>
<span style="color: #777777;">[ 0.000350] pid_max: default: 32768 minimum: 301</span>
<span style="color: #777777;">[ 0.000557] LSM: Security Framework initializing</span>
<span style="color: #777777;">[ 0.000827] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes, linear)</span>
<span style="color: #777777;">[ 0.000863] Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes, linear)</span>
<span style="color: #777777;">[ 0.002356] Disabling memory control group subsystem</span>
<span style="color: #777777;">[ 0.004396] ASID allocator initialised with 32768 entries</span>
<span style="color: #777777;">[ 0.004678] rcu: Hierarchical SRCU implementation.</span>
<span style="color: #777777;">[ 0.005371] EFI services will not be available.</span>
<span style="color: #777777;">[ 0.005935] smp: Bringing up secondary CPUs ...</span>
<span style="color: #777777;">[ 0.007351] Detected VIPT I-cache on CPU1</span>
<span style="color: #777777;">[ 0.007419] CPU1: Booted secondary processor 0x0000000001 [0x410fd034]</span>
<span style="color: #777777;">[ 0.009359] Detected VIPT I-cache on CPU2</span>
<span style="color: #777777;">[ 0.009410] CPU2: Booted secondary processor 0x0000000002 [0x410fd034]</span>
<span style="color: #777777;">[ 0.011221] Detected VIPT I-cache on CPU3</span>
<span style="color: #777777;">[ 0.011268] CPU3: Booted secondary processor 0x0000000003 [0x410fd034]</span>
<span style="color: #777777;">[ 0.011885] smp: Brought up 1 node, 4 CPUs</span>
<span style="color: #777777;">[ 0.011937] SMP: Total of 4 processors activated.</span>
<span style="color: #777777;">[ 0.011957] CPU features: detected: 32-bit EL0 Support</span>
<span style="color: #777777;">[ 0.011978] CPU features: detected: CRC32 instructions</span>
<span style="color: #777777;">[ 0.037684] CPU: All CPU(s) started at EL2</span>
<span style="color: #777777;">[ 0.037762] alternatives: patching kernel code</span>
<span style="color: #777777;">[ 0.039583] devtmpfs: initialized</span>
<span style="color: #777777;">[ 0.056561] Enabled cp15_barrier support</span>
<span style="color: #777777;">[ 0.056610] Enabled setend support</span>
<span style="color: #777777;">[ 0.057401] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275000 ns</span>
<span style="color: #777777;">[ 0.057438] futex hash table entries: 1024 (order: 4, 65536 bytes, linear)</span>
<span style="color: #777777;">[ 0.070451] pinctrl core: initialized pinctrl subsystem</span>
<span style="color: #777777;">[ 0.070834] DMI not present or invalid.</span>
<span style="color: #777777;">[ 0.071361] NET: Registered protocol family 16</span>
<span style="color: #777777;">[ 0.080371] DMA: preallocated 1024 KiB pool for atomic allocations</span>
<span style="color: #777777;">[ 0.080464] audit: initializing netlink subsys (disabled)</span>
<span style="color: #777777;">[ 0.080858] audit: type=2000 audit(0.079:1): state=initialized audit_enabled=0 res=1</span>
<span style="color: #777777;">[ 0.081662] cpuidle: using governor menu</span>
<span style="color: #777777;">[ 0.081950] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.</span>
<span style="color: #777777;">[ 0.082313] Serial: AMBA PL011 UART driver</span>
<span style="color: #777777;">[ 0.085113] bcm2835-mbox 3f00b880.mailbox: mailbox enabled</span>
<span style="color: #777777;">[ 0.095260] raspberrypi-firmware soc:firmware: Attached to firmware from 2020-10-02 16:09, variant start</span>
<span style="color: #777777;">[ 0.096274] raspberrypi-firmware soc:firmware: Firmware hash is 4672d0274057d726f3a327e2b3fe76f831b811bb</span>
<span style="color: #777777;">[ 0.140930] bcm2835-dma 3f007000.dma: DMA legacy API manager, dmachans=0x1</span>
<span style="color: #777777;">[ 0.143534] SCSI subsystem initialized</span>
<span style="color: #777777;">[ 0.143880] usbcore: registered new interface driver usbfs</span>
<span style="color: #777777;">[ 0.143957] usbcore: registered new interface driver hub</span>
<span style="color: #777777;">[ 0.144141] usbcore: registered new device driver usb</span>
<span style="color: #777777;">[ 0.145929] clocksource: Switched to clocksource arch_sys_counter</span>
<span style="color: #777777;">[ 1.429264] VFS: Disk quotas dquot_6.6.0</span>
<span style="color: #777777;">[ 1.429409] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)</span>
<span style="color: #777777;">[ 1.429643] FS-Cache: Loaded</span>
<span style="color: #777777;">[ 1.430056] CacheFiles: Loaded</span>
<span style="color: #777777;">[ 1.444000] thermal_sys: Registered thermal governor 'step_wise'</span>
<span style="color: #777777;">[ 1.444462] NET: Registered protocol family 2</span>
<span style="color: #777777;">[ 1.445522] tcp_listen_portaddr_hash hash table entries: 512 (order: 1, 8192 bytes, linear)</span>
<span style="color: #777777;">[ 1.445576] TCP established hash table entries: 8192 (order: 4, 65536 bytes, linear)</span>
<span style="color: #777777;">[ 1.445702] TCP bind hash table entries: 8192 (order: 5, 131072 bytes, linear)</span>
<span style="color: #777777;">[ 1.445964] TCP: Hash tables configured (established 8192 bind 8192)</span>
<span style="color: #777777;">[ 1.446214] UDP hash table entries: 512 (order: 2, 16384 bytes, linear)</span>
<span style="color: #777777;">[ 1.446276] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes, linear)</span>
<span style="color: #777777;">[ 1.446645] NET: Registered protocol family 1</span>
<span style="color: #777777;">[ 1.447835] RPC: Registered named UNIX socket transport module.</span>
<span style="color: #777777;">[ 1.447855] RPC: Registered udp transport module.</span>
<span style="color: #777777;">[ 1.447872] RPC: Registered tcp transport module.</span>
<span style="color: #777777;">[ 1.447889] RPC: Registered tcp NFSv4.1 backchannel transport module.</span>
<span style="color: #777777;">[ 1.449642] hw perfevents: enabled with armv8_cortex_a53 PMU driver, 7 counters available</span>
<span style="color: #777777;">[ 1.452049] Initialise system trusted keyrings</span>
<span style="color: #777777;">[ 1.452478] workingset: timestamp_bits=46 max_order=18 bucket_order=0</span>
<span style="color: #777777;">[ 1.466411] FS-Cache: Netfs 'nfs' registered for caching</span>
<span style="color: #777777;">[ 1.467485] NFS: Registering the id_resolver key type</span>
<span style="color: #777777;">[ 1.467593] Key type id_resolver registered</span>
<span style="color: #777777;">[ 1.467612] Key type id_legacy registered</span>
<span style="color: #777777;">[ 1.467643] nfs4filelayout_init: NFSv4 File Layout Driver Registering...</span>
<span style="color: #777777;">[ 1.469406] Key type asymmetric registered</span>
<span style="color: #777777;">[ 1.469429] Asymmetric key parser 'x509' registered</span>
<span style="color: #777777;">[ 1.469494] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 249)</span>
<span style="color: #777777;">[ 1.469517] io scheduler mq-deadline registered</span>
<span style="color: #777777;">[ 1.469536] io scheduler kyber registered</span>
<span style="color: #777777;">[ 1.478032] Serial: 8250/16550 driver, 1 ports, IRQ sharing enabled</span>
<span style="color: #777777;">[ 1.481110] bcm2835-rng 3f104000.rng: hwrng registered</span>
<span style="color: #777777;">[ 1.481721] vc-mem: phys_addr:0x00000000 mem_base=0x3ec00000 mem_size:0x40000000(1024 MiB)</span>
<span style="color: #777777;">[ 1.482825] gpiomem-bcm2835 3f200000.gpiomem: Initialised: Registers at 0x3f200000</span>
<span style="color: #777777;">[ 1.483358] cacheinfo: Unable to detect cache hierarchy for CPU 0</span>
<span style="color: #777777;">[ 1.499607] brd: module loaded</span>
<span style="color: #777777;">[ 1.517239] loop: module loaded</span>
<span style="color: #777777;">[ 1.518966] Loading iSCSI transport class v2.0-870.</span>
<span style="color: #777777;">[ 1.520136] libphy: Fixed MDIO Bus: probed</span>
<span style="color: #777777;">[ 1.520290] usbcore: registered new interface driver lan78xx</span>
<span style="color: #777777;">[ 1.520369] usbcore: registered new interface driver smsc95xx</span>
<span style="color: #777777;">[ 1.520399] dwc_otg: version 3.00a 10-AUG-2012 (platform bus)</span>
<span style="color: #777777;">[ 2.249221] Core Release: 2.80a</span>
<span style="color: #777777;">[ 2.249243] Setting default values for core params</span>
<span style="color: #777777;">[ 2.249280] Finished setting default values for core params</span>
<span style="color: #777777;">[ 2.449973] Using Buffer DMA mode</span>
<span style="color: #777777;">[ 2.449993] Periodic Transfer Interrupt Enhancement - disabled</span>
<span style="color: #777777;">[ 2.450010] Multiprocessor Interrupt Enhancement - disabled</span>
<span style="color: #777777;">[ 2.450029] OTG VER PARAM: 0, OTG VER FLAG: 0</span>
<span style="color: #777777;">[ 2.450052] Dedicated Tx FIFOs mode</span>
<span style="color: #777777;">[ 2.451562] WARN::dwc_otg_hcd_init:1072: FIQ DMA bounce buffers: virt = ffffffc010251000 dma = 0x00000000ded00000 len=9024</span>
<span style="color: #777777;">[ 2.451597] FIQ FSM acceleration enabled for :</span>
<span style="color: #777777;">[ 2.451597] Non-periodic Split Transactions</span>
<span style="color: #777777;">[ 2.451597] Periodic Split Transactions</span>
<span style="color: #777777;">[ 2.451597] High-Speed Isochronous Endpoints</span>
<span style="color: #777777;">[ 2.451597] Interrupt/Control Split Transaction hack enabled</span>
<span style="color: #777777;">[ 2.451660] WARN::hcd_init_fiq:496: MPHI regs_base at ffffffc01005d000</span>
<span style="color: #777777;">[ 2.451711] dwc_otg 3f980000.usb: DWC OTG Controller</span>
<span style="color: #777777;">[ 2.451755] dwc_otg 3f980000.usb: new USB bus registered, assigned bus number 1</span>
<span style="color: #777777;">[ 2.451830] dwc_otg 3f980000.usb: irq 9, io mem 0x00000000</span>
<span style="color: #777777;">[ 2.451886] Init: Port Power? op_state=1</span>
<span style="color: #777777;">[ 2.451933] Init: Power Port (0)</span>
<span style="color: #777777;">[ 2.452382] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 5.04</span>
<span style="color: #777777;">[ 2.452407] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1</span>
<span style="color: #777777;">[ 2.452429] usb usb1: Product: DWC OTG Controller</span>
<span style="color: #777777;">[ 2.452451] usb usb1: Manufacturer: Linux 5.4.69-v8 dwc_otg_hcd</span>
<span style="color: #777777;">[ 2.452472] usb usb1: SerialNumber: 3f980000.usb</span>
<span style="color: #777777;">[ 2.453459] hub 1-0:1.0: USB hub found</span>
<span style="color: #777777;">[ 2.453542] hub 1-0:1.0: 1 port detected</span>
<span style="color: #777777;">[ 2.455546] usbcore: registered new interface driver usb-storage</span>
<span style="color: #777777;">[ 2.457384] bcm2835-wdt bcm2835-wdt: Broadcom BCM2835 watchdog timer</span>
<span style="color: #777777;">[ 2.461090] sdhci: Secure Digital Host Controller Interface driver</span>
<span style="color: #777777;">[ 2.461110] sdhci: Copyright(c) Pierre Ossman</span>
<span style="color: #777777;">[ 2.461765] mmc-bcm2835 3f300000.mmcnr: could not get clk, deferring probe</span>
<span style="color: #777777;">[ 2.462539] sdhost-bcm2835 3f202000.mmc: could not get clk, deferring probe</span>
<span style="color: #777777;">[ 2.462837] sdhci-pltfm: SDHCI platform and OF driver helper</span>
<span style="color: #777777;">[ 2.464815] ledtrig-cpu: registered to indicate activity on CPUs</span>
<span style="color: #777777;">[ 2.465298] hidraw: raw HID events driver (C) Jiri Kosina</span>
<span style="color: #777777;">[ 2.465494] usbcore: registered new interface driver usbhid</span>
<span style="color: #777777;">[ 2.465512] usbhid: USB HID core driver</span>
<span style="color: #777777;">[ 2.466076] ashmem: initialized</span>
<span style="color: #777777;">[ 2.466719] Initializing XFRM netlink socket</span>
<span style="color: #777777;">[ 2.466774] NET: Registered protocol family 17</span>
<span style="color: #777777;">[ 2.466984] Key type dns_resolver registered</span>
<span style="color: #777777;">[ 2.467565] registered taskstats version 1</span>
<span style="color: #777777;">[ 2.467596] Loading compiled-in X.509 certificates</span>
<span style="color: #777777;">[ 2.468032] Key type ._fscrypt registered</span>
<span style="color: #777777;">[ 2.468052] Key type .fscrypt registered</span>
<span style="color: #777777;">[ 2.484212] uart-pl011 3f201000.serial: cts_event_workaround enabled</span>
<span style="color: #777777;">[ 2.484349] 3f201000.serial: ttyAMA0 at MMIO 0x3f201000 (irq = 66, base_baud = 0) is a PL011 rev2</span>
<span style="color: #777777;">[ 2.487448] printk: console [ttyS0] disabled</span>
<span style="color: #777777;">[ 2.487542] 3f215040.serial: ttyS0 at MMIO 0x0 (irq = 61, base_baud = 50000000) is a 16550</span>
<span style="color: #777777;">[ 3.473145] printk: console [ttyS0] enabled</span>
<span style="color: #777777;">[ 3.478603] bcm2835-power bcm2835-power: Broadcom BCM2835 power domains driver</span>
<span style="color: #777777;">[ 3.487779] mmc-bcm2835 3f300000.mmcnr: mmc_debug:0 mmc_debug2:0</span>
<span style="color: #777777;">[ 3.493937] mmc-bcm2835 3f300000.mmcnr: DMA channel allocated</span>
<span style="color: #777777;">[ 3.526207] sdhost: log_buf @ (____ptrval____) (f8e51000)</span>
<span style="color: #777777;">[ 3.551613] mmc1: queuing unknown CIS tuple 0x80 (2 bytes)</span>
<span style="color: #777777;">[ 3.558881] mmc1: queuing unknown CIS tuple 0x80 (3 bytes)</span>
<span style="color: #777777;">[ 3.566201] mmc1: queuing unknown CIS tuple 0x80 (3 bytes)</span>
<span style="color: #777777;">[ 3.574850] mmc1: queuing unknown CIS tuple 0x80 (7 bytes)</span>
<span style="color: #777777;">[ 3.585510] Indeed it is in host mode hprt0 = 00021501</span>
<span style="color: #777777;">[ 3.592974] mmc0: sdhost-bcm2835 loaded - DMA enabled (>1)</span>
<span style="color: #777777;">[ 3.602767] of_cfs_init</span>
<span style="color: #777777;">[ 3.605452] of_cfs_init: OK</span>
<span style="color: #777777;">[ 3.610371] Waiting for root device /dev/mmcblk0p2...</span>
<span style="color: #777777;">[ 3.664973] random: fast init done</span>
<span style="color: #777777;">[ 3.729776] mmc1: new high speed SDIO card at address 0001</span>
<span style="color: #777777;">[ 3.747467] mmc0: host does not support reading read-only switch, assuming write-enable</span>
<span style="color: #777777;">[ 3.762580] mmc0: new high speed SDHC card at address aaaa</span>
<span style="color: #777777;">[ 3.769519] mmcblk0: mmc0:aaaa SL16G 14.8 GiB</span>
<span style="color: #777777;">[ 3.774047] usb 1-1: new high-speed USB device number 2 using dwc_otg</span>
<span style="color: #777777;">[ 3.780896] Indeed it is in host mode hprt0 = 00001101</span>
<span style="color: #777777;">[ 3.797189] mmcblk0: p1 p2</span>
<span style="color: #777777;">[ 3.815991] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)</span>
<span style="color: #777777;">[ 3.824333] VFS: Mounted root (ext4 filesystem) readonly on device 179:2.</span>
<span style="color: #777777;">[ 3.835841] devtmpfs: mounted</span>
<span style="color: #777777;">[ 3.848102] Freeing unused kernel memory: 3072K</span>
<span style="color: #777777;">[ 3.852800] Run /sbin/init as init process</span>
<span style="color: #777777;">INIT: version 2.97 booting</span>
<span style="color: #777777;">[ 3.978789] usb 1-1: New USB device found, idVendor=0424, idProduct=9514, bcdDevice= 2.00</span>
<span style="color: #777777;">[ 3.987214] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0</span>
<span style="color: #777777;">[ 3.995769] hub 1-1:1.0: USB hub found</span>
<span style="color: #777777;">[ 3.999985] hub 1-1:1.0: 5 ports detected</span>
<span style="color: #777777;">Framebuffer /dev/fb0 not detected</span>
<span style="color: #777777;">Boot splashscreen disabled</span>
<span style="color: #777777;">[ 4.293048] usb 1-1.1: new high-speed USB device number 3 using dwc_otg</span>
<span style="color: #777777;">[ 4.388594] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00, bcdDevice= 2.00</span>
<span style="color: #777777;">[ 4.397199] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0</span>
<span style="color: #777777;">[ 4.408145] smsc95xx v1.0.6</span>
<span style="color: #777777;">[ 4.460223] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-3f980000.usb-1.1, smsc95xx USB 2.0 Ethernet, b8:27:eb:fd:e3:45</span>
<span style="color: #777777;">Starting udev</span>
<span style="color: #777777;">[ 4.701746] udevd[119]: starting version 3.2.9</span>
<span style="color: #777777;">[ 4.738668] random: udevd: uninitialized urandom read (16 bytes read)</span>
<span style="color: #777777;">[ 4.746220] random: udevd: uninitialized urandom read (16 bytes read)</span>
<span style="color: #777777;">[ 4.758069] random: udevd: uninitialized urandom read (16 bytes read)</span>
<span style="color: #777777;">[ 4.808414] udevd[120]: starting eudev-3.2.9</span>
<span style="color: #777777;">[ 4.911884] random: crng init done</span>
<span style="color: #777777;">[ 4.915359] random: 3 urandom warning(s) missed due to ratelimiting</span>
<span style="color: #777777;">[ 4.970283] vchiq: module is from the staging directory, the quality is unknown, you have been warned.</span>
<span style="color: #777777;">[ 4.998866] vchiq: vchiq_init_state: slot_zero = 00000000ae5c87c4</span>
<span style="color: #777777;">[ 5.197187] vc_sm_cma: module is from the staging directory, the quality is unknown, you have been warned.</span>
<span style="color: #777777;">[ 5.206689] cfg80211: Loading compiled-in X.509 certificates for regulatory database</span>
<span style="color: #777777;">[ 5.216350] bcm2835_vc_sm_cma_probe: Videocore shared memory driver</span>
<span style="color: #777777;">[ 5.222796] [vc_sm_connected_init]: start</span>
<span style="color: #777777;">[ 5.228112] [vc_sm_connected_init]: installed successfully</span>
<span style="color: #777777;">[ 5.234222] snd_bcm2835: module is from the staging directory, the quality is unknown, you have been warned.</span>
<span style="color: #777777;">[ 5.251418] bcm2835_audio bcm2835_audio: card created with 8 channels</span>
<span style="color: #777777;">[ 5.270497] mc: Linux media interface: v0.10</span>
<span style="color: #777777;">[ 5.330355] videodev: Linux video capture interface: v2.00</span>
<span style="color: #777777;">[ 5.342758] cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'</span>
<span style="color: #777777;">[ 5.352409] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2</span>
<span style="color: #777777;">[ 5.361291] cfg80211: failed to load regulatory.db</span>
<span style="color: #777777;">[ 5.374974] vc4-drm soc:gpu: bound 3f600000.firmwarekms (ops vc4_fkms_ops [vc4])</span>
<span style="color: #777777;">[ 5.382958] vc4-drm soc:gpu: bound 3fc00000.v3d (ops vc4_v3d_ops [vc4])</span>
<span style="color: #777777;">[ 5.389812] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).</span>
<span style="color: #777777;">[ 5.396598] [drm] No driver support for vblank timestamp query.</span>
<span style="color: #777777;">[ 5.402747] [drm] Setting vblank_disable_immediate to false because get_vblank_timestamp == NULL</span>
<span style="color: #777777;">[ 5.413321] [drm] Initialized vc4 0.0.0 20140616 for soc:gpu on minor 0</span>
<span style="color: #777777;">[ 5.478261] bcm2835_mmal_vchiq: module is from the staging directory, the quality is unknown, you have been warned.</span>
<span style="color: #777777;">[ 5.478633] bcm2835_mmal_vchiq: module is from the staging directory, the quality is unknown, you have been warned.</span>
<span style="color: #777777;">[ 5.479494] bcm2835_mmal_vchiq: module is from the staging directory, the quality is unknown, you have been warned.</span>
<span style="color: #777777;">[ 5.481108] Console: switching to colour frame buffer device 90x30</span>
<span style="color: #777777;">[ 5.496212] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43430-sdio for chip BCM43430/1</span>
<span style="color: #777777;">[ 5.496585] usbcore: registered new interface driver brcmfmac</span>
<span style="color: #777777;">[ 5.550829] vc4-drm soc:gpu: fb0: vc4drmfb frame buffer device</span>
<span style="color: #777777;">[ 5.561091] bcm2835_v4l2: module is from the staging directory, the quality is unknown, you have been warned.</span>
<span style="color: #777777;">[ 5.598697] bcm2835_codec: module is from the staging directory, the quality is unknown, you have been warned.</span>
<span style="color: #777777;">[ 5.609303] bcm2835_isp: module is from the staging directory, the quality is unknown, you have been warned.</span>
<span style="color: #777777;">[ 5.624981] bcm2835-codec bcm2835-codec: Device registered as /dev/video10</span>
<span style="color: #777777;">[ 5.625067] bcm2835-codec bcm2835-codec: Loaded V4L2 decode</span>
<span style="color: #777777;">[ 5.639147] bcm2835-isp bcm2835-isp: Device node output[0] registered as /dev/video13</span>
<span style="color: #777777;">[ 5.647793] bcm2835-isp bcm2835-isp: Device node capture[0] registered as /dev/video14</span>
<span style="color: #777777;">[ 5.656481] bcm2835-isp bcm2835-isp: Device node capture[1] registered as /dev/video15</span>
<span style="color: #777777;">[ 5.656588] bcm2835-codec bcm2835-codec: Device registered as /dev/video11</span>
<span style="color: #777777;">[ 5.665123] bcm2835-isp bcm2835-isp: Device node stats[2] registered as /dev/video16</span>
<span style="color: #777777;">[ 5.671659] bcm2835-codec bcm2835-codec: Loaded V4L2 encode</span>
<span style="color: #777777;">[ 5.679485] bcm2835-isp bcm2835-isp: Register output node 0 with media controller</span>
<span style="color: #777777;">[ 5.679507] bcm2835-isp bcm2835-isp: Register capture node 1 with media controller</span>
<span style="color: #777777;">[ 5.679526] bcm2835-isp bcm2835-isp: Register capture node 2 with media controller</span>
<span style="color: #777777;">[ 5.708379] bcm2835-isp bcm2835-isp: Register capture node 3 with media controller</span>
<span style="color: #777777;">[ 5.716471] bcm2835-isp bcm2835-isp: Loaded V4L2 bcm2835-isp</span>
<span style="color: #777777;">[ 5.723339] bcm2835-codec bcm2835-codec: Device registered as /dev/video12</span>
<span style="color: #777777;">[ 5.730762] bcm2835-codec bcm2835-codec: Loaded V4L2 isp</span>
<span style="color: #777777;">[ 5.837048] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)</span>
<span style="color: #777777;">[ 5.860586] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43430-sdio for chip BCM43430/1</span>
<span style="color: #777777;">[ 5.869718] brcmfmac: brcmf_c_process_clm_blob: no clm_blob available (err=-2), device may have limited channels available</span>
<span style="color: #777777;">[ 5.882177] brcmfmac: brcmf_c_preinit_dcmds: Firmware: BCM43430/1 wl0: Oct 22 2019 01:59:28 version 7.45.98.94 (r723000 CY) FWID 01-3b33decd</span>
<span style="color: #777777;">Fri Mar 9 12:34:56 UTC 2018</span>
<span style="color: #777777;">chmod: cannot access '/var/log/wtmp': No such file or directory</span>
<span style="color: #777777;">Failed to set mode -0664- for -/var/log/wtmp-.</span>
<span style="color: #777777;">Configuring packages on first boot....</span>
<span style="color: #777777;"> (This may take several minutes. Please do not power off the machine.)</span>
<span style="color: #777777;">Running postinst /etc/ipk-postinsts/000-sysvinit-inittab...</span>
<span style="color: #777777;">update-rc.d: /etc/init.d/run-postinsts exists during rc.d purge (continuing)</span>
<span style="color: #777777;"> Removing any system startup links for run-postinsts ...</span>
<span style="color: #777777;"> /etc/rcS.d/S99run-postinsts</span>
<span style="color: #777777;">INIT: Entering runlevel: 5</span>
<span style="color: #777777;">Configuring network interfaces... [ 7.341201] smsc95xx 1-1.1:1.0 eth0: hardware isn't capable of remote wakeup</span>
<span style="color: #777777;">udhcpc: started, v1.32.0</span>
<span style="color: #777777;">udhcpc: sending discover</span>
<span style="color: #777777;">udhcpc: sending discover</span>
<span style="color: #777777;">udhcpc: sending discover</span>
<span style="color: #777777;">udhcpc: no lease, forking to background</span>
<span style="color: #777777;">done.</span>
<span style="color: #777777;">Starting system message bus: dbus.</span>
<span style="color: #777777;">Starting random number generator daemon.</span>
<span style="color: #777777;">Starting OpenBSD Secure Shell server: sshd</span>
<span style="color: #777777;"> generating ssh RSA host key...</span>
<span style="color: #777777;"> generating ssh ECDSA host key...</span>
<span style="color: #777777;"> generating ssh ED25519 host key...</span>
<span style="color: #777777;">[ 21.472551] NET: Registered protocol family 10</span>
<span style="color: #777777;">[ 21.486542] Segment Routing with IPv6</span>
<span style="color: #777777;">done.</span>
<span style="color: #777777;">Starting rpcbind daemon...done.</span>
<span style="color: #777777;">starting statd: done</span>
<span style="color: #777777;">Starting atd: OK</span>
<span style="color: #777777;">[ 21.992880] Installing knfsd (copyright (C) 1996 okir@monad.swb.de).</span>
<span style="color: #777777;">starting 8 nfsd kernel threads: [ 23.151164] NFSD: Using /var/lib/nfs/v4recovery as the NFSv4 state recovery directory</span>
<span style="color: #777777;">[ 23.163714] NFSD: Using legacy client tracking operations.</span>
<span style="color: #777777;">[ 23.169445] NFSD: starting 90-second grace period (net f00004c1)</span>
<span style="color: #777777;">done</span>
<span style="color: #777777;">starting mountd: done</span>
<span style="color: #777777;">Starting system log daemon...0</span>
<span style="color: #777777;">Starting crond: OK</span>
<span style="color: #777777;">umount: /mnt/.psplash: no mount point specified.</span>
<span style="color: #777777;">Poky (Yocto Project Reference Distro) 3.1+snapshot raspberrypi3-64 ttyS0</span>
<span style="color: #777777;">raspberrypi3-64 login: </span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Good! Now we have a solid base on which to work with our device!</p><h2 style="text-align: left;">Adding Software</h2><p style="text-align: left;">As I mentioned earlier, the Pimoroni Automation-HAT comes with a python library to help you get up and running with your device. But how do you get that library onto the device? In theory you could install <span style="font-family: courier; font-size: x-small;">pip</span> (and whatever it requires) into your image, run that image on the device, connect the device to the internet, and install the library by hand. But this isn't what we want. We don't want to generate a partial image that then needs manual intervention in the production stage. What if we were preparing 20 such devices? The moment human intervention is involved, the chances for errors goes up… <i>significantly</i>! What happens when all our devices are provisioned and we then discover we need to make a fix or add more steps?</p><p style="text-align: left;">What we want is a way to build a fully complete master image on the host that has all the software we need with everything configured and ready to go. Flash a µSD card, insert it into the device, add power, and it's up and running. Not: flash the µSD card, insert it into the device, log into the device, make sure the network is running, run a bunch of comands by hand…</p><p style="text-align: left;">The way we add things to an OpenEmbedded image is to create a <i>recipe</i>. OE layers are full of recipes. There are thousands and thousands of recipes for all sorts of software and situations. The first thing we do is to check to see if someone else had already written a recipe for the software we want to add. To do this we check the layer index: <a href="http://layers.openembedded.org/">http://layers.openembedded.org/</a>. Select <i>Recipes</i>, enter a string, and click <i>search</i>. Unfortunately there doesn't seem to be any pre-existing recipes for us.</p><p style="text-align: left;">We could just write a recipe from scratch. But before resorting to that scenario, we could use <i>devtool</i>. <i>Devtool</i> is a tool that is part of OpenEmbedded that helps users to create and maintain recipes. Before asking <i>devtool</i> to create the recipe for us, we have to understand what it is we want to build. We start off by visiting the code's website: <a href="https://github.com/pimoroni/automation-hat" target="_blank">https://github.com/pimoroni/automation-hat</a></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-_TOV4BlyyEk/X3pxtpJr0bI/AAAAAAAAiYw/bhQnSdtlEqYDm3h6dGMVlXOIBQXQbRL1wCLcBGAsYHQ/s825/github-01.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="825" src="https://1.bp.blogspot.com/-_TOV4BlyyEk/X3pxtpJr0bI/AAAAAAAAiYw/bhQnSdtlEqYDm3h6dGMVlXOIBQXQbRL1wCLcBGAsYHQ/s16000/github-01.png" /></a></div><br /><p style="text-align: left;">Along the right-hand side, we see that this project has produced releases, but that the last release was about 5 months ago. There have been 8 commits since the last release. Therefore I think it would be best to work from the master branch's HEAD commit instead of the release.</p><p style="text-align: left;">Continuing to work in the same shell that was setup earlier, the same one we've been using to <i>bitbake</i> all our builds so far:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool add --srcrev a41084cb4db02b76fc536235321a613d1c88ba52 automation-hat https://github.com/pimoroni/automation-hat.git
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Creating workspace layer in /z/build-master/6951/automation-hat/poky/build/workspace</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Fetching git://github.com/pimoroni/automation-hat.git;protocol=https;nobranch=1...</span>
<span style="color: #777777;">Loading cache: 100% | | ETA: --:--:--</span>
<span style="color: #777777;">Loaded 0 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:06</span>
<span style="color: #777777;">Parsing of 815 .bb files complete (0 cached, 815 parsed). 1384 targets, 65 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "<unknown>:<unknown>"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Found 0 Missed 0 Current 0 (0% match, 0% complete)</span>
<span style="color: #777777;">NOTE: No setscene tasks</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 2 tasks of which 0 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 0 seconds</span>
<span style="color: #777777;">INFO: Using default source tree path /z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Using source tree as build directory since that would be the default for this recipe</span>
<span style="color: #777777;">INFO: Recipe /z/build-master/6951/automation-hat/poky/build/workspace/recipes/automation-hat/automation-hat_git.bb has been automatically created; further editing may be required to make it fully functional</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">As the comment says, we should take a look at what <i>devtool</i> created to see if it needs any tweaking. But where do we find the recipe <i>devtool</i> just created? Technically <i>devtool</i> created a workspace for you and put the recipe there. But we don't even need to know that detail since we can just let <i>devtool</i> do all the work:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool edit-recipe automation-hat
</pre></td></tr></tbody></table></div>
<p style="text-align: left;"><i>Devtool</i> will locate the recipe for you and open it in your $EDITOR. As we can see <i>devtool</i> created some parts of the recipe, but it only did a so-so job. It doesn't appear to know how to handle this python library particularly well:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;"># Recipe created by recipetool</span>
<span style="color: #777777; font-style: italic;"># This is the basis of a recipe and may need further editing in order to be fully functional.</span>
<span style="color: #777777; font-style: italic;"># (Feel free to remove these comments when editing.)</span>
<span style="color: #777777; font-style: italic;"># WARNING: the following LICENSE and LIC_FILES_CHKSUM values are best guesses - it is</span>
<span style="color: #777777; font-style: italic;"># your responsibility to verify that the values are complete and correct.</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #777777; font-style: italic;"># The following license files were not able to be identified and are</span>
<span style="color: #777777; font-style: italic;"># represented as "Unknown" below, you will need to check them yourself:</span>
<span style="color: #777777; font-style: italic;"># packaging/debian/copyright</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #777777; font-style: italic;"># NOTE: multiple licenses have been detected; they have been separated with &</span>
<span style="color: #777777; font-style: italic;"># in the LICENSE value for now since it is a reasonable assumption that all</span>
<span style="color: #777777; font-style: italic;"># of the licenses apply. If instead there is a choice between the multiple</span>
<span style="color: #777777; font-style: italic;"># licenses then you should change the value to separate the licenses with |</span>
<span style="color: #777777; font-style: italic;"># instead of &. If there is any doubt, check the accompanying documentation</span>
<span style="color: #777777; font-style: italic;"># to determine which situation is applicable.</span>
<span style="color: #2db5b5;">LICENSE</span> = <span style="color: #bf7f0f;">"MIT & Unknown"</span>
<span style="color: #2db5b5;">LIC_FILES_CHKSUM</span> = <span style="color: #bf7f0f;">"file://LICENSE;md5=1be647ba1f2b40ff716e997a3e4a0d47 \</span>
<span style="color: #bf7f0f;"> file://library/LICENSE.txt;md5=1be647ba1f2b40ff716e997a3e4a0d47 \</span>
<span style="color: #bf7f0f;"> file://packaging/debian/copyright;md5=711b00d4d30e94965c8a959ae574dcc2"</span>
<span style="color: #2db5b5;">SRC_URI</span> = <span style="color: #bf7f0f;">"git://github.com/pimoroni/automation-hat.git;protocol=https"</span>
<span style="color: #777777; font-style: italic;"># Modify these as desired</span>
<span style="color: #2db5b5;">PV</span> = <span style="color: #bf7f0f;">"1.0+git</span><span style="color: #777777; font-style: italic;">${SRCPV}</span><span style="color: #bf7f0f;">"</span>
<span style="color: #2db5b5;">SRCREV</span> = <span style="color: #bf7f0f;">"a41084cb4db02b76fc536235321a613d1c88ba52"</span>
<span style="color: #2db5b5;">S</span> = <span style="color: #bf7f0f;">"</span><span style="color: #777777; font-style: italic;">${WORKDIR}</span><span style="color: #bf7f0f;">/git"</span>
<span style="color: #777777; font-style: italic;"># NOTE: this is a Makefile-only piece of software, so we cannot generate much of the</span>
<span style="color: #777777; font-style: italic;"># recipe automatically - you will need to examine the Makefile yourself and ensure</span>
<span style="color: #777777; font-style: italic;"># that the appropriate arguments are passed in.</span>
do_configure () {
<span style="color: #777777; font-style: italic;"># Specify any needed configure commands here</span>
:
}
do_compile () {
<span style="color: #777777; font-style: italic;"># You will almost certainly need to add additional arguments here</span>
oe_runmake
}
do_install () {
<span style="color: #777777; font-style: italic;"># This is a guess; additional arguments may be required</span>
oe_runmake install
}
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Good recipes should have a <span style="font-family: courier; font-size: x-small;">SUMMARY</span>, a <span style="font-family: courier; font-size: x-small;">DESCRIPTION</span>, and a <span style="font-family: courier; font-size: x-small;">HOMEPAGE</span> tag (among others). Also, experience dictates that OpenEmbedded includes many recipes for dealing with python libraries. Chances are good there's already a <i>bbclass</i> that takes care of this situation. A little investigation leads to the <i>setuptools3</i> class:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">SUMMARY</span> = <span style="color: #bf7f0f;">"Pimoroni Automation-HAT python library"</span>
<span style="color: #2db5b5;">DESCRIPTION</span> = <span style="color: #bf7f0f;">"Automation HAT is a home monitoring and automation controller \</span>
<span style="color: #bf7f0f;">featuring relays, analog channels, powered outputs, and buffered inputs \</span>
<span style="color: #bf7f0f;">(all 24V tolerant)."</span>
<span style="color: #2db5b5;">HOMEPAGE</span> = <span style="color: #bf7f0f;">"https://shop.pimoroni.com/products/automation-hat"</span>
<span style="color: #2db5b5;">SECTION</span> = <span style="color: #bf7f0f;">"iot/python"</span>
<span style="color: #2db5b5;">LICENSE</span> = <span style="color: #bf7f0f;">"MIT & Unknown"</span>
<span style="color: #2db5b5;">LIC_FILES_CHKSUM</span> = <span style="color: #bf7f0f;">"file://LICENSE;md5=1be647ba1f2b40ff716e997a3e4a0d47 \</span>
<span style="color: #bf7f0f;"> file://library/LICENSE.txt;md5=1be647ba1f2b40ff716e997a3e4a0d47 \</span>
<span style="color: #bf7f0f;"> file://packaging/debian/copyright;md5=711b00d4d30e94965c8a959ae574dcc2"</span>
<span style="color: #2db5b5;">SRC_URI</span> = <span style="color: #bf7f0f;">"git://github.com/pimoroni/automation-hat.git;protocol=https"</span>
<span style="color: #2db5b5;">PV</span> = <span style="color: #bf7f0f;">"1.0+git</span><span style="color: #777777; font-style: italic;">${SRCPV}</span><span style="color: #bf7f0f;">"</span>
<span style="color: #2db5b5;">SRCREV</span> = <span style="color: #bf7f0f;">"a41084cb4db02b76fc536235321a613d1c88ba52"</span>
<span style="color: #2db5b5;">S</span> = <span style="color: #bf7f0f;">"</span><span style="color: #777777; font-style: italic;">${WORKDIR}</span><span style="color: #bf7f0f;">/git"</span>
<span style="color: #6ab825; font-weight: bold;">inherit</span> <span style="color: #447fcf; text-decoration: underline;">setuptools3</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Now we try building:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool build automation-hat
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 1384 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 815 .bb files complete (814 cached, 1 parsed). 1384 targets, 65 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Loaded 1384 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 815 .bb files complete (814 cached, 1 parsed). 1384 targets, 65 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Found 0 Missed 0 Current 190 (0% match, 100% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: automation-hat: compiling from external source tree /z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat</span>
<span style="color: #777777;">ERROR: automation-hat-1.0+git999-r0 do_compile: 'python3 setup.py build ' execution failed.</span>
<span style="color: #777777;">ERROR: automation-hat-1.0+git999-r0 do_compile: Execution of '/z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069' failed with exit code 1:</span>
<span style="color: #777777;">/z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/recipe-sysroot-native/usr/bin/python3-native/python3: can't open file '/z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat/setup.py': [Errno 2] No such file or directory</span>
<span style="color: #777777;">WARNING: /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069:175 exit 1 from 'exit 1'</span>
<span style="color: #777777;">WARNING: Backtrace (BB generated script): </span>
<span style="color: #777777;"> #1: bbfatal_log, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 175</span>
<span style="color: #777777;"> #2: distutils3_do_compile, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 165</span>
<span style="color: #777777;"> #3: do_compile, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 154</span>
<span style="color: #777777;"> #4: main, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 179</span>
<span style="color: #777777;">Backtrace (metadata-relative locations):</span>
<span style="color: #777777;"> #1: bbfatal_log, /opt/oe/configs/z/build-master/6951/automation-hat/poky/layers/poky/meta/classes/logging.bbclass, line 72</span>
<span style="color: #777777;"> #2: distutils3_do_compile, /opt/oe/configs/z/build-master/6951/automation-hat/poky/layers/poky/meta/classes/distutils3.bbclass, line 26</span>
<span style="color: #777777;"> #3: do_compile, autogenerated, line 2</span>
<span style="color: #777777;">ERROR: Logfile of failure stored in: /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/log.do_compile.16069</span>
<span style="color: #777777;">Log data follows:</span>
<span style="color: #777777;">| DEBUG: Executing python function externalsrc_compile_prefunc</span>
<span style="color: #777777;">| NOTE: automation-hat: compiling from external source tree /z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat</span>
<span style="color: #777777;">| DEBUG: Python function externalsrc_compile_prefunc finished</span>
<span style="color: #777777;">| DEBUG: Executing shell function do_compile</span>
<span style="color: #777777;">| /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/recipe-sysroot-native/usr/bin/python3-native/python3: can't open file '/z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat/setup.py': [Errno 2] No such file or directory</span>
<span style="color: #777777;">| ERROR: 'python3 setup.py build ' execution failed.</span>
<span style="color: #777777;">| WARNING: /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069:175 exit 1 from 'exit 1'</span>
<span style="color: #777777;">| WARNING: Backtrace (BB generated script):</span>
<span style="color: #777777;">| #1: bbfatal_log, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 175</span>
<span style="color: #777777;">| #2: distutils3_do_compile, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 165</span>
<span style="color: #777777;">| #3: do_compile, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 154</span>
<span style="color: #777777;">| #4: main, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 179</span>
<span style="color: #777777;">| ERROR: Execution of '/z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069' failed with exit code 1:</span>
<span style="color: #777777;">| /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/recipe-sysroot-native/usr/bin/python3-native/python3: can't open file '/z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat/setup.py': [Errno 2] No such file or directory</span>
<span style="color: #777777;">| WARNING: /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069:175 exit 1 from 'exit 1'</span>
<span style="color: #777777;">| WARNING: Backtrace (BB generated script):</span>
<span style="color: #777777;">| #1: bbfatal_log, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 175</span>
<span style="color: #777777;">| #2: distutils3_do_compile, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 165</span>
<span style="color: #777777;">| #3: do_compile, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 154</span>
<span style="color: #777777;">| #4: main, /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp/run.do_compile.16069, line 179</span>
<span style="color: #777777;">| </span>
<span style="color: #777777;">| Backtrace (metadata-relative locations):</span>
<span style="color: #777777;">| #1: bbfatal_log, /opt/oe/configs/z/build-master/6951/automation-hat/poky/layers/poky/meta/classes/logging.bbclass, line 72</span>
<span style="color: #777777;">| #2: distutils3_do_compile, /opt/oe/configs/z/build-master/6951/automation-hat/poky/layers/poky/meta/classes/distutils3.bbclass, line 26</span>
<span style="color: #777777;">| #3: do_compile, autogenerated, line 2</span>
<span style="color: #777777;">ERROR: Task (/z/build-master/6951/automation-hat/poky/build/workspace/recipes/automation-hat/automation-hat_git.bb:do_compile) failed with exit code '1'</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 723 tasks of which 719 didn't need to be rerun and 1 failed.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 1 seconds</span>
<span style="color: #777777;">NOTE: Build completion summary:</span>
<span style="color: #777777;">NOTE: do_deploy_source_date_epoch: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">Summary: 1 task failed:</span>
<span style="color: #777777;"> /z/build-master/6951/automation-hat/poky/build/workspace/recipes/automation-hat/automation-hat_git.bb:do_compile</span>
<span style="color: #777777;">Summary: There were 2 ERROR messages shown, returning a non-zero exit code.</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Looking through the error message we can see that the <i>setuptools3 bbclass</i> is not able to find the <span style="font-family: courier; font-size: x-small;">setup.py</span> file from the library. Looking through the sources we see that the <span style="font-family: courier; font-size: x-small;">setup.py</span> file is found in the <i>library</i> subdirectory. Therefore we edit the recipe again and tweak:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">SUMMARY = "Pimoroni Automation-HAT python library"</span>
<span style="color: #777777;">DESCRIPTION = "Automation HAT is a home monitoring and automation controller \</span>
<span style="color: #777777;">featuring relays, analog channels, powered outputs, and buffered inputs \</span>
<span style="color: #777777;">(all 24V tolerant)."</span>
<span style="color: #777777;">HOMEPAGE = "https://shop.pimoroni.com/products/automation-hat"</span>
<span style="color: #777777;">SECTION = "iot/python"</span>
<span style="color: #777777;">LICENSE = "MIT & Unknown"</span>
<span style="color: #777777;">LIC_FILES_CHKSUM = "file://LICENSE;md5=1be647ba1f2b40ff716e997a3e4a0d47 \</span>
<span style="color: #777777;"> file://library/LICENSE.txt;md5=1be647ba1f2b40ff716e997a3e4a0d47 \</span>
<span style="color: #777777;"> file://packaging/debian/copyright;md5=711b00d4d30e94965c8a959ae574dcc2"</span>
<span style="color: #777777;">SRC_URI = "git://github.com/pimoroni/automation-hat.git;protocol=https"</span>
<span style="color: #777777;">PV = "1.0+git${SRCPV}"</span>
<span style="color: #777777;">SRCREV = "a41084cb4db02b76fc536235321a613d1c88ba52"</span>
<span style="color: #2db5b5;">S</span> = <span style="color: #bf7f0f;">"</span><span color="#777777' font-style: italic">${WORKDIR}</span><span style="color: #bf7f0f;">/git/library"</span>
<span style="color: #777777;">inherit setuptools3</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">We build again… <i>and we get the same error</i>? Now we need to dig a little deeper. If we've modified the <span style="font-family: courier; font-size: x-small;">S</span> variable explicitly, why is the build still looking in the old location? Now we ask <i>bitbake</i> to explain itself: "bitbake what do you know about the S variable?":</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake automation-hat -e | grep <span style="color: #bf7f0f;">"^S="</span>
<span style="color: #777777;">S="/z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat"</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">This is very perplexing. We're setting the S variable explicitly in our recipe, but something is overriding it. If we look deeper into the <i>workspace</i> directory that <i>devtool</i> creates for us, we find:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> tree workspace
<span style="color: #777777;">workspace</span>
<span style="color: #777777;">├── README</span>
<span style="color: #777777;">├── appends</span>
<span style="color: #777777;">│ └── automation-hat_git.bbappend</span>
<span style="color: #777777;">├── conf</span>
<span style="color: #777777;">│ └── layer.conf</span>
<span style="color: #777777;">├── recipes</span>
<span style="color: #777777;">│ └── automation-hat</span>
<span style="color: #777777;">│ └── automation-hat_git.bb</span>
<span style="color: #777777;">└── sources</span>
<span style="color: #777777;"> └── automation-hat</span>
<span style="color: #777777;"> ├── LICENSE</span>
<span style="color: #777777;"> ├── Makefile</span>
<span style="color: #777777;"> ├── README.md</span>
<span style="color: #777777;"> ├── autohat_360.png</span>
<span style="color: #777777;"> ├── documentation</span>
<span style="color: #777777;"> │ └── REFERENCE.md</span>
<span style="color: #777777;"> ├── examples</span>
<span style="color: #777777;"> │ ├── hat</span>
<span style="color: #777777;"> │ │ ├── analog.py</span>
<span style="color: #777777;"> │ │ ├── input.py</span>
<span style="color: #777777;"> │ │ ├── lights.py</span>
<span style="color: #777777;"> │ │ ├── output.py</span>
<span style="color: #777777;"> │ │ └── relay.py</span>
<span style="color: #777777;"> │ └── hat-mini</span>
<span style="color: #777777;"> │ ├── analog.py</span>
<span style="color: #777777;"> │ ├── images</span>
<span style="color: #777777;"> │ │ ├── analog-inputs-blank.jpg</span>
<span style="color: #777777;"> │ │ ├── inputs-blank.jpg</span>
<span style="color: #777777;"> │ │ └── outputs-blank.jpg</span>
<span style="color: #777777;"> │ ├── input.py</span>
<span style="color: #777777;"> │ └── output.py</span>
<span style="color: #777777;"> ├── library</span>
<span style="color: #777777;"> │ ├── CHANGELOG.txt</span>
<span style="color: #777777;"> │ ├── LICENSE.txt</span>
<span style="color: #777777;"> │ ├── MANIFEST.in</span>
<span style="color: #777777;"> │ ├── README.rst</span>
<span style="color: #777777;"> │ ├── automationhat</span>
<span style="color: #777777;"> │ │ ├── __init__.py</span>
<span style="color: #777777;"> │ │ ├── ads1015.py</span>
<span style="color: #777777;"> │ │ └── pins.py</span>
<span style="color: #777777;"> │ ├── setup.py</span>
<span style="color: #777777;"> │ ├── test.py</span>
<span style="color: #777777;"> │ ├── tests</span>
<span style="color: #777777;"> │ │ └── test_setup.py</span>
<span style="color: #777777;"> │ └── tox.ini</span>
<span style="color: #777777;"> ├── oe-logs -> /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0/temp</span>
<span style="color: #777777;"> ├── oe-workdir -> /z/build-master/6951/automation-hat/poky/build/tmp/work/cortexa53-poky-linux/automation-hat/1.0+git999-r0</span>
<span style="color: #777777;"> ├── packaging</span>
<span style="color: #777777;"> │ ├── CHANGELOG</span>
<span style="color: #777777;"> │ ├── debian</span>
<span style="color: #777777;"> │ │ ├── README</span>
<span style="color: #777777;"> │ │ ├── changelog</span>
<span style="color: #777777;"> │ │ ├── clean</span>
<span style="color: #777777;"> │ │ ├── compat</span>
<span style="color: #777777;"> │ │ ├── control</span>
<span style="color: #777777;"> │ │ ├── copyright</span>
<span style="color: #777777;"> │ │ ├── docs</span>
<span style="color: #777777;"> │ │ ├── rules</span>
<span style="color: #777777;"> │ │ └── source</span>
<span style="color: #777777;"> │ │ ├── format</span>
<span style="color: #777777;"> │ │ └── options</span>
<span style="color: #777777;"> │ ├── makeall.sh</span>
<span style="color: #777777;"> │ ├── makedeb.sh</span>
<span style="color: #777777;"> │ └── makelog.sh</span>
<span style="color: #777777;"> └── terminal.jpg</span>
<span style="color: #777777;">19 directories, 46 files</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Snooping around in the <i>workspace</i> I'm curious about the <i>bbappend</i>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5
6</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> cat workspace/appends/automation-hat_git.bbappend
<span style="color: #777777;">inherit externalsrc</span>
<span style="color: #777777;">EXTERNALSRC = "/z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat"</span>
<span style="color: #777777;">EXTERNALSRC_BUILD = "/z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat"</span>
<span style="color: #777777;"># initial_rev: a41084cb4db02b76fc536235321a613d1c88ba52</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">It's pulling in the <i>externalsrc bbclass</i>. I wonder what the <i>externalsrc bbclass</i> does and whether or not it plays with the <span style="font-family: courier; font-size: x-small;">S</span> variable? Turns out it does! Looking at the top part of the <i>externalsrc bbclass</i>:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;"># Copyright (C) 2012 Linux Foundation</span>
<span style="color: #777777; font-style: italic;"># Author: Richard Purdie</span>
<span style="color: #777777; font-style: italic;"># Some code and influence taken from srctree.bbclass:</span>
<span style="color: #777777; font-style: italic;"># Copyright (C) 2009 Chris Larson <clarson@kergoth.com></span>
<span style="color: #777777; font-style: italic;"># Released under the MIT license (see COPYING.MIT for the terms)</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #777777; font-style: italic;"># externalsrc.bbclass enables use of an existing source tree, usually external to</span>
<span style="color: #777777; font-style: italic;"># the build system to build a piece of software rather than the usual fetch/unpack/patch</span>
<span style="color: #777777; font-style: italic;"># process.</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #777777; font-style: italic;"># To use, add externalsrc to the global inherit and set EXTERNALSRC to point at the</span>
<span style="color: #777777; font-style: italic;"># directory you want to use containing the sources e.g. from local.conf for a recipe</span>
<span style="color: #777777; font-style: italic;"># called "myrecipe" you would do:</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #777777; font-style: italic;"># INHERIT += "externalsrc"</span>
<span style="color: #777777; font-style: italic;"># EXTERNALSRC_pn-myrecipe = "/path/to/my/source/tree"</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #777777; font-style: italic;"># In order to make this class work for both target and native versions (or with</span>
<span style="color: #777777; font-style: italic;"># multilibs/cross or other BBCLASSEXTEND variants), B is set to point to a separate</span>
<span style="color: #777777; font-style: italic;"># directory under the work directory (split source and build directories). This is</span>
<span style="color: #777777; font-style: italic;"># the default, but the build directory can be set to the source directory if</span>
<span style="color: #777777; font-style: italic;"># circumstances dictate by setting EXTERNALSRC_BUILD to the same value, e.g.:</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #777777; font-style: italic;"># EXTERNALSRC_BUILD_pn-myrecipe = "/path/to/my/source/tree"</span>
<span style="color: #777777; font-style: italic;">#</span>
<span style="color: #2db5b5;">SRCTREECOVEREDTASKS</span> ?= <span style="color: #bf7f0f;">"do_patch do_unpack do_fetch"</span>
<span style="color: #2db5b5;">EXTERNALSRC_SYMLINKS</span> ?= <span style="color: #bf7f0f;">"oe-workdir:</span><span style="color: #777777; font-style: italic;">${WORKDIR}</span><span style="color: #bf7f0f;"> oe-logs:</span><span style="color: #777777; font-style: italic;">${T}</span><span style="color: #bf7f0f;">"</span>
<span style="color: #447fcf;">python</span> () {
<span style="color: #2db5b5;">externalsrc</span> = d.getVar(<span style="color: #bf7f0f;">'EXTERNALSRC'</span>)
<span style="color: #2db5b5;">externalsrcbuild</span> = d.getVar(<span style="color: #bf7f0f;">'EXTERNALSRC_BUILD'</span>)
<span style="color: #6ab825; font-weight: bold;">if</span> externalsrc and not externalsrc.startswith(<span style="color: #bf7f0f;">"/"</span>):
bb.error(<span style="color: #bf7f0f;">"EXTERNALSRC must be an absolute path"</span>)
<span style="color: #6ab825; font-weight: bold;">if</span> externalsrcbuild and not externalsrcbuild.startswith(<span style="color: #bf7f0f;">"/"</span>):
bb.error(<span style="color: #bf7f0f;">"EXTERNALSRC_BUILD must be an absolute path"</span>)
<span style="color: #777777; font-style: italic;"># If this is the base recipe and EXTERNALSRC is set for it or any of its</span>
<span style="color: #777777; font-style: italic;"># derivatives, then enable BB_DONT_CACHE to force the recipe to always be</span>
<span style="color: #777777; font-style: italic;"># re-parsed so that the file-checksums function for do_compile is run every</span>
<span style="color: #777777; font-style: italic;"># time.</span>
<span style="color: #2db5b5;">bpn</span> = d.getVar(<span style="color: #bf7f0f;">'BPN'</span>)
<span style="color: #2db5b5;">classextend</span> = (d.getVar(<span style="color: #bf7f0f;">'BBCLASSEXTEND'</span>) or <span style="color: #bf7f0f;">''</span>).split()
<span style="color: #6ab825; font-weight: bold;">if</span> <span style="color: #2db5b5;">bpn</span> == d.getVar(<span style="color: #bf7f0f;">'PN'</span>) or not classextend:
<span style="color: #6ab825; font-weight: bold;">if</span> (externalsrc or
(<span style="color: #bf7f0f;">'native'</span> in classextend and
d.getVar(<span style="color: #bf7f0f;">'EXTERNALSRC_pn-%s-native'</span> % bpn)) or
(<span style="color: #bf7f0f;">'nativesdk'</span> in classextend and
d.getVar(<span style="color: #bf7f0f;">'EXTERNALSRC_pn-nativesdk-%s'</span> % bpn)) or
(<span style="color: #bf7f0f;">'cross'</span> in classextend and
d.getVar(<span style="color: #bf7f0f;">'EXTERNALSRC_pn-%s-cross'</span> % bpn))):
d.setVar(<span style="color: #bf7f0f;">'BB_DONT_CACHE'</span>, <span style="color: #bf7f0f;">'1'</span>)
<span style="color: #6ab825; font-weight: bold;">if</span> externalsrc:
import oe.recipeutils
import oe.path
d.setVar(<span style="color: #bf7f0f;">'S'</span>, externalsrc)
<span style="color: #6ab825; font-weight: bold;">if</span> externalsrcbuild:
d.setVar(<span style="color: #bf7f0f;">'B'</span>, externalsrcbuild)
<span style="color: #6ab825; font-weight: bold;">else</span>:
d.setVar(<span style="color: #bf7f0f;">'B'</span>, <span style="color: #bf7f0f;">'${WORKDIR}/${BPN}-${PV}/'</span>)
…
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">We can see on line 59 that the <span style="font-family: courier; font-size: x-small;">S</span> variable is being set to <span style="font-family: courier; font-size: x-small;">externalsrc</span>, which is being set on line 31 to the value of <span style="font-family: courier; font-size: x-small;">EXTERNALSRC</span> which it finds in the <span style="font-family: courier; font-size: x-small;">automation-hat.bbappend</span> file. Therefore if we tweak the <span style="font-family: courier; font-size: x-small;">automation-hat.bbappend</span><span style="font-family: courier; font-size: small;"> </span>file it should be able to find our <span style="font-family: courier; font-size: x-small;">setup.py</span> code:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5
6</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> cat workspace/appends/automation-hat_git.bbappend
<span style="color: #777777;">inherit externalsrc</span>
<span style="color: #777777;">EXTERNALSRC = "/z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat/library"</span>
<span style="color: #777777;">EXTERNALSRC_BUILD = "/z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat/library"</span>
<span style="color: #777777;"># initial_rev: a41084cb4db02b76fc536235321a613d1c88ba52</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">and build:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool build automation-hat
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 1384 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 815 .bb files complete (814 cached, 1 parsed). 1384 targets, 65 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Loaded 1384 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 815 .bb files complete (814 cached, 1 parsed). 1384 targets, 65 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Found 0 Missed 0 Current 190 (0% match, 100% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: automation-hat: compiling from external source tree /z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat/library</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 727 tasks of which 721 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 0 seconds</span>
<span style="color: #777777;">NOTE: Build completion summary:</span>
<span style="color: #777777;">NOTE: do_populate_sysroot: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_package: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_packagedata: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Phew!</p><p style="text-align: left;">However, this isn't the "correct" solution. Turns out <i>devtool</i> has an option for this very situation (i.e. the <i>setup.py</i> not being in the top-level directory of a repository). If we look at the options available for <i>devtool add</i> we find:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool add
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">devtool add: error: At least one of recipename, srctree, fetchuri or -f/--fetch must be specified</span>
<span style="color: #777777;">usage: devtool add [-h] [--same-dir | --no-same-dir] [--fetch URI] [--npm-dev]</span>
<span style="color: #777777;"> [--version VERSION] [--no-git]</span>
<span style="color: #777777;"> [--srcrev SRCREV | --autorev] [--srcbranch SRCBRANCH]</span>
<span style="color: #777777;"> [--binary] [--also-native] [--src-subdir SUBDIR]</span>
<span style="color: #777777;"> [--mirrors] [--provides PROVIDES]</span>
<span style="color: #777777;"> [recipename] [srctree] [fetchuri]</span>
<span style="color: #777777;">Adds a new recipe to the workspace to build a specified source tree. Can</span>
<span style="color: #777777;">optionally fetch a remote URI and unpack it to create the source tree.</span>
<span style="color: #777777;">arguments:</span>
<span style="color: #777777;"> recipename Name for new recipe to add (just name - no version,</span>
<span style="color: #777777;"> path or extension). If not specified, will attempt to</span>
<span style="color: #777777;"> auto-detect it.</span>
<span style="color: #777777;"> srctree Path to external source tree. If not specified, a</span>
<span style="color: #777777;"> subdirectory of /z/build-master/6951/automation-</span>
<span style="color: #777777;"> hat/build/workspace/sources will be used.</span>
<span style="color: #777777;"> fetchuri Fetch the specified URI and extract it to create the</span>
<span style="color: #777777;"> source tree</span>
<span style="color: #777777;">options:</span>
<span style="color: #777777;"> -h, --help show this help message and exit</span>
<span style="color: #777777;"> --same-dir, -s Build in same directory as source</span>
<span style="color: #777777;"> --no-same-dir Force build in a separate build directory</span>
<span style="color: #777777;"> --fetch URI, -f URI Fetch the specified URI and extract it to create the</span>
<span style="color: #777777;"> source tree (deprecated - pass as positional argument</span>
<span style="color: #777777;"> instead)</span>
<span style="color: #777777;"> --npm-dev For npm, also fetch devDependencies</span>
<span style="color: #777777;"> --version VERSION, -V VERSION</span>
<span style="color: #777777;"> Version to use within recipe (PV)</span>
<span style="color: #777777;"> --no-git, -g If fetching source, do not set up source tree as a git</span>
<span style="color: #777777;"> repository</span>
<span style="color: #777777;"> --srcrev SRCREV, -S SRCREV</span>
<span style="color: #777777;"> Source revision to fetch if fetching from an SCM such</span>
<span style="color: #777777;"> as git (default latest)</span>
<span style="color: #777777;"> --autorev, -a When fetching from a git repository, set SRCREV in the</span>
<span style="color: #777777;"> recipe to a floating revision instead of fixed</span>
<span style="color: #777777;"> --srcbranch SRCBRANCH, -B SRCBRANCH</span>
<span style="color: #777777;"> Branch in source repository if fetching from an SCM</span>
<span style="color: #777777;"> such as git (default master)</span>
<span style="color: #777777;"> --binary, -b Treat the source tree as something that should be</span>
<span style="color: #777777;"> installed verbatim (no compilation, same directory</span>
<span style="color: #777777;"> structure). Useful with binary packages e.g. RPMs.</span>
<span style="color: #777777;"> --also-native Also add native variant (i.e. support building recipe</span>
<span style="color: #777777;"> for the build host as well as the target machine)</span>
<span style="color: #777777;"> --src-subdir SUBDIR Specify subdirectory within source tree to use</span>
<span style="color: #777777;"> --mirrors Enable PREMIRRORS and MIRRORS for source tree fetching</span>
<span style="color: #777777;"> (disable by default).</span>
<span style="color: #777777;"> --provides PROVIDES, -p PROVIDES</span>
<span style="color: #777777;"> Specify an alias for the item provided by the recipe.</span>
<span style="color: #777777;"> E.g. virtual/libgl</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">So let's try creating the recipe again with the <i>--src-subdir</i> option:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool add --srcrev a41084cb4db02b76fc536235321a613d1c88ba52 --src-subdir library automation-hat https://github.com/pimoroni/automation-hat.git
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">ERROR: recipe automation-hat is already in your workspace</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">We have to clean out the workspace before we can try again (if we want to use the same recipe name):</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool reset automation-hat
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Cleaning sysroot for recipe automation-hat...</span>
<span style="color: #777777;">WARNING: File automation-hat_git.bb modified since it was written, preserving in /z/build-master/6951/automation-hat/poky/build/workspace/attic/automation-hat</span>
<span style="color: #777777;">WARNING: File automation-hat_git.bbappend modified since it was written, preserving in /z/build-master/6951/automation-hat/poky/build/workspace/attic/automation-hat</span>
<span style="color: #777777;">INFO: Leaving source tree /z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat/library as-is; if you no longer need it then please delete it manually</span>
<span style="color: #348c00;">$</span> rm -fr workspace/sources/automation-hat/
<span style="color: #348c00;">$</span> devtool add --srcrev a41084cb4db02b76fc536235321a613d1c88ba52 --src-subdir library automation-hat https://github.com/pimoroni/automation-hat.git
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Fetching git://github.com/pimoroni/automation-hat.git;protocol=https;nobranch=1...</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Loaded 1384 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 815 .bb files complete (814 cached, 1 parsed). 1384 targets, 65 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">Removing 1 recipes from the cortexa53 sysroot: 100% |###########################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Removing 1 recipes from the raspberrypi3_64 sysroot: 100% |#####################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Found 0 Missed 0 Current 0 (0% match, 0% complete)</span>
<span style="color: #777777;">NOTE: No setscene tasks</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 2 tasks of which 0 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 1 seconds</span>
<span style="color: #777777;">INFO: Scanning paths for packages & dependencies: automationhat</span>
<span style="color: #777777;">INFO: Using default source tree path /z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat</span>
<span style="color: #777777;">WARNING: A modified recipe from a previous invocation exists in /z/build-master/6951/automation-hat/poky/build/workspace/attic/automation-hat/automation-hat_git.bb - you may wish to move this over the top of the new recipe if you had changes in it that you want to continue with</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Recipe /z/build-master/6951/automation-hat/poky/build/workspace/recipes/automation-hat/automation-hat_git.bb has been automatically created; further editing may be required to make it fully functional</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">When we look at the recipe <i>devtool</i> generated for us we find a lot of improvements:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;"># Recipe created by recipetool</span>
<span style="color: #777777; font-style: italic;"># This is the basis of a recipe and may need further editing in order to be fully functional.</span>
<span style="color: #777777; font-style: italic;"># (Feel free to remove these comments when editing.)</span>
<span style="color: #2db5b5;">SUMMARY</span> = <span style="color: #bf7f0f;">"Automation HAT Driver"</span>
<span style="color: #2db5b5;">HOMEPAGE</span> = <span style="color: #bf7f0f;">"http://www.pimoroni.com"</span>
<span style="color: #777777; font-style: italic;"># WARNING: the following LICENSE and LIC_FILES_CHKSUM values are best guesses - it is</span>
<span style="color: #777777; font-style: italic;"># your responsibility to verify that the values are complete and correct.</span>
<span style="color: #2db5b5;">LICENSE</span> = <span style="color: #bf7f0f;">"MIT"</span>
<span style="color: #2db5b5;">LIC_FILES_CHKSUM</span> = <span style="color: #bf7f0f;">"file://LICENSE.txt;md5=1be647ba1f2b40ff716e997a3e4a0d47"</span>
<span style="color: #2db5b5;">SRC_URI</span> = <span style="color: #bf7f0f;">"git://github.com/pimoroni/automation-hat.git;protocol=https"</span>
<span style="color: #777777; font-style: italic;"># Modify these as desired</span>
<span style="color: #2db5b5;">PV</span> = <span style="color: #bf7f0f;">"0.2.2+git</span><span style="color: #777777; font-style: italic;">${SRCPV}</span><span style="color: #bf7f0f;">"</span>
<span style="color: #2db5b5;">SRCREV</span> = <span style="color: #bf7f0f;">"a41084cb4db02b76fc536235321a613d1c88ba52"</span>
<span style="color: #2db5b5;">S</span> = <span style="color: #bf7f0f;">"</span><span style="color: #777777; font-style: italic;">${WORKDIR}</span><span style="color: #bf7f0f;">/git/library"</span>
<span style="color: #6ab825; font-weight: bold;">inherit</span> <span style="color: #447fcf; text-decoration: underline;">setuptools3</span>
<span style="color: #777777; font-style: italic;"># WARNING: the following rdepends are from setuptools install_requires. These</span>
<span style="color: #777777; font-style: italic;"># upstream names may not correspond exactly to bitbake package names.</span>
<span style="color: #2db5b5;">RDEPENDS_${PN}</span> += <span style="color: #bf7f0f;">"python3-rpi-gpio python3-st7735 python3-sn3218"</span>
<span style="color: #777777; font-style: italic;"># WARNING: the following rdepends are determined through basic analysis of the</span>
<span style="color: #777777; font-style: italic;"># python sources, and might not be 100% accurate.</span>
<span style="color: #2db5b5;">RDEPENDS_${PN}</span> += <span style="color: #bf7f0f;">"python3-core"</span>
<span style="color: #777777; font-style: italic;"># WARNING: We were unable to map the following python package/module</span>
<span style="color: #777777; font-style: italic;"># dependencies to the bitbake packages which include them:</span>
<span style="color: #777777; font-style: italic;"># smbus</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;"></p><ul style="text-align: left;"><li>line 5: <i>devtool</i> found a summary (although I'd prefer to change it to "Automation-HAT Python Library")</li><li>line 6: <i>devtool</i> found a homepage (although I'd prefer to point it to the specific product, not just the company's website)</li><li>lines 9-10: it's clearer about the license</li><li>line 15: it found a version (although the latest version is 0.2.3, not 0.2.2)</li><li>line 18: it set the S variable correctly</li><li>line 20: <i>devtool</i> discovered that it could use <i>setuptools3</i> to build</li><li>lines 24 and 28: <i>devtool</i> found a couple runtime dependencies</li></ul><p style="text-align: left;">This is great! This is a much nicer recipe to use as a starting point. Good job <i>devtool</i>.</p><p style="text-align: left;">After a little cleaning up, my recipe now looks like:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">SUMMARY</span> = <span style="color: #bf7f0f;">"Automation-HAT Python Library"</span>
<span style="color: #2db5b5;">DESCRIPTION</span> = <span style="color: #bf7f0f;">"Automation HAT is a home monitoring and automation controller \</span>
<span style="color: #bf7f0f;">featuring relays, analog channels, powered outputs, and buffered inputs (all \</span>
<span style="color: #bf7f0f;">24V tolerant)."</span>
<span style="color: #2db5b5;">HOMEPAGE</span> = <span style="color: #bf7f0f;">"https://shop.pimoroni.com/products/automation-hat"</span>
<span style="color: #2db5b5;">LICENSE</span> = <span style="color: #bf7f0f;">"MIT"</span>
<span style="color: #2db5b5;">LIC_FILES_CHKSUM</span> = <span style="color: #bf7f0f;">"file://LICENSE.txt;md5=1be647ba1f2b40ff716e997a3e4a0d47"</span>
<span style="color: #2db5b5;">SRC_URI</span> = <span style="color: #bf7f0f;">"git://github.com/pimoroni/automation-hat.git;protocol=https"</span>
<span style="color: #2db5b5;">PV</span> = <span style="color: #bf7f0f;">"0.2.3+git</span><span style="color: #777777; font-style: italic;">${SRCPV}</span><span style="color: #bf7f0f;">"</span>
<span style="color: #2db5b5;">SRCREV</span> = <span style="color: #bf7f0f;">"a41084cb4db02b76fc536235321a613d1c88ba52"</span>
<span style="color: #2db5b5;">S</span> = <span style="color: #bf7f0f;">"</span><span style="color: #777777; font-style: italic;">${WORKDIR}</span><span style="color: #bf7f0f;">/git/library"</span>
<span style="color: #6ab825; font-weight: bold;">inherit</span> <span style="color: #447fcf; text-decoration: underline;">setuptools3</span>
<span style="color: #2db5b5;">RDEPENDS_${PN}</span> += <span style="color: #bf7f0f;">"rpi-gpio python3-smbus python3-sn3218 python3-core"</span>
</pre></td></tr></tbody></table></div>
<p></p><p style="text-align: left;"></p><ul style="text-align: left;"><li>line 1: I've updated the summary</li><li>line 2: I've added a description</li><li>line 5: I've updated the homepage</li><li>I've verified the license and therefore removed the comment warning me to check it by hand</li><li>line 11: I've updated the version</li><li>I've removed the comments around the runtime dependencies</li><li>line 18: I've changed the name of the <i>python3-rpi-gpio</i> runtime dependency to <i>rpi-gpio</i> and I've removed the <i>python3-st7735</i> runtime dependency since I don't have the ST7735 TFT display attached to my setup. I've consolidated the two <span style="font-family: courier; font-size: x-small;">RDEPENDS</span> lines, and figured out that the recipe needs a runtime dependency on <i>python3-smbus</i></li></ul><p style="text-align: left;">Searching the <a href="http://layers.openembedded.org/" target="_blank">OpenEmbedded layer index</a> for the names of the runtime dependencies that <i>devtool</i> has identified in creating this recipe, I found that a recipe already exists for <i>rpi-gpio</i> (it's in the <i>meta-raspberrypi</i> BSP layer, which we're already using), so I updated the name to match. A recipe for the other runtime dependency, <i>python3-sn3218</i>, isn't available and this is probably because this repository is also from Pimoroni's github account.</p><p style="text-align: left;">There's no point trying to build the <i>automation-hat</i> recipe until we've attempted to satisfy all of its (runtime) dependencies so we invoke <i>devtool</i> again:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool add --version <span style="color: #3677a9;">1</span>.2.7 --srcrev d497c6e9762c6d31bd9a7f9da9ccef0318b8e31c --src-subdir library python3-sn3218 https://github.com/pimoroni/sn3218
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Fetching git://github.com/pimoroni/sn3218;protocol=https;nobranch=1...</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Loaded 1385 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 816 .bb files complete (814 cached, 2 parsed). 1385 targets, 65 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Found 0 Missed 0 Current 0 (0% match, 0% complete)</span>
<span style="color: #777777;">NOTE: No setscene tasks</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 2 tasks of which 0 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 1 seconds</span>
<span style="color: #777777;">INFO: Scanning paths for packages & dependencies: sn3218.py</span>
<span style="color: #777777;">INFO: Using default source tree path /z/build-master/6951/automation-hat/poky/build/workspace/sources/python3-sn3218</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">INFO: Recipe /z/build-master/6951/automation-hat/poky/build/workspace/recipes/python3-sn3218/python3-sn3218_git.bb has been automatically created; further editing may be required to make it fully functional</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Looking at the resulting recipe:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777; font-style: italic;"># Recipe created by recipetool</span>
<span style="color: #777777; font-style: italic;"># This is the basis of a recipe and may need further editing in order to be fully functional.</span>
<span style="color: #777777; font-style: italic;"># (Feel free to remove these comments when editing.)</span>
<span style="color: #2db5b5;">SUMMARY</span> = <span style="color: #bf7f0f;">"A module to drive the sn3218 i2c LED controller"</span>
<span style="color: #2db5b5;">HOMEPAGE</span> = <span style="color: #bf7f0f;">"http://www.pimoroni.com"</span>
<span style="color: #777777; font-style: italic;"># WARNING: the following LICENSE and LIC_FILES_CHKSUM values are best guesses - it is</span>
<span style="color: #777777; font-style: italic;"># your responsibility to verify that the values are complete and correct.</span>
<span style="color: #2db5b5;">LICENSE</span> = <span style="color: #bf7f0f;">"MIT"</span>
<span style="color: #2db5b5;">LIC_FILES_CHKSUM</span> = <span style="color: #bf7f0f;">"file://LICENSE.txt;md5=be85037b505b21b386e82d53cd928b5e"</span>
<span style="color: #2db5b5;">SRC_URI</span> = <span style="color: #bf7f0f;">"git://github.com/pimoroni/sn3218;protocol=https"</span>
<span style="color: #777777; font-style: italic;"># Modify these as desired</span>
<span style="color: #2db5b5;">PV</span> = <span style="color: #bf7f0f;">"1.2.7+git</span><span style="color: #777777; font-style: italic;">${SRCPV}</span><span style="color: #bf7f0f;">"</span>
<span style="color: #2db5b5;">SRCREV</span> = <span style="color: #bf7f0f;">"d497c6e9762c6d31bd9a7f9da9ccef0318b8e31c"</span>
<span style="color: #2db5b5;">S</span> = <span style="color: #bf7f0f;">"</span><span style="color: #777777; font-style: italic;">${WORKDIR}</span><span style="color: #bf7f0f;">/git/library"</span>
<span style="color: #6ab825; font-weight: bold;">inherit</span> <span style="color: #447fcf; text-decoration: underline;">setuptools3</span>
<span style="color: #777777; font-style: italic;"># WARNING: the following rdepends are determined through basic analysis of the</span>
<span style="color: #777777; font-style: italic;"># python sources, and might not be 100% accurate.</span>
<span style="color: #2db5b5;">RDEPENDS_${PN}</span> += <span style="color: #bf7f0f;">"python3-core"</span>
<span style="color: #777777; font-style: italic;"># WARNING: We were unable to map the following python package/module</span>
<span style="color: #777777; font-style: italic;"># dependencies to the bitbake packages which include them:</span>
<span style="color: #777777; font-style: italic;"># smbus</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">This recipe is looking pretty good already. I simply need to clean up some of the preamble tags, and remove most of the comments that <i>devtool</i> has placed into the file for my attention:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #2db5b5;">SUMMARY</span> = <span style="color: #bf7f0f;">"A module to drive the sn3218 i2c LED controller"</span>
<span style="color: #2db5b5;">HOMEPAGE</span> = <span style="color: #bf7f0f;">"https://github.com/pimoroni/sn3218"</span>
<span style="color: #2db5b5;">LICENSE</span> = <span style="color: #bf7f0f;">"MIT"</span>
<span style="color: #2db5b5;">LIC_FILES_CHKSUM</span> = <span style="color: #bf7f0f;">"file://LICENSE.txt;md5=be85037b505b21b386e82d53cd928b5e"</span>
<span style="color: #2db5b5;">SRC_URI</span> = <span style="color: #bf7f0f;">"git://github.com/pimoroni/sn3218;protocol=https"</span>
<span style="color: #2db5b5;">PV</span> = <span style="color: #bf7f0f;">"1.2.7+git</span><span style="color: #777777; font-style: italic;">${SRCPV}</span><span style="color: #bf7f0f;">"</span>
<span style="color: #2db5b5;">SRCREV</span> = <span style="color: #bf7f0f;">"d497c6e9762c6d31bd9a7f9da9ccef0318b8e31c"</span>
<span style="color: #2db5b5;">S</span> = <span style="color: #bf7f0f;">"</span><span style="color: #777777; font-style: italic;">${WORKDIR}</span><span style="color: #bf7f0f;">/git/library"</span>
<span style="color: #6ab825; font-weight: bold;">inherit</span> <span style="color: #447fcf; text-decoration: underline;">setuptools3</span>
<span style="color: #2db5b5;">RDEPENDS_${PN}</span> += <span style="color: #bf7f0f;">"python3-smbus python3-core"</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">You may have noticed the reference to <i>smbus</i> by both recipes. <i>smbus</i> is another way of saying <i>i2c</i>, so I make a note that I probably want to add <i>i2c</i> user-space tools to my build. This makes sense since most (all?) of the peripherals on the Automation-HAT interface to the Raspberry Pi via i2c. This change needs to be done in my <span style="font-family: courier; font-size: x-small;">conf/local.conf</span>.</p><p style="text-align: left;">But what about the <i>smbus</i> runtime dependency itself? If we search the <a href="http://layers.openembedded.org/" target="_blank">layer index</a> we find that there already is a recipe for <a href="http://layers.openembedded.org/layerindex/recipe/60953/" target="_blank">python3-smbus</a> in <span style="font-family: courier; font-size: x-small;">meta-python</span>, which is part of <span style="font-family: courier; font-size: x-small;">meta-openembedded</span>. Currently we're not using <span style="font-family: courier; font-size: x-small;">meta-openembeded</span> in our build, therefore we need to clone that repository too, and add it to our build layers. We could do it manually or:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake-layers layerindex-fetch -b master meta-python
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">Loading https://layers.openembedded.org/layerindex/api/;branch=master...</span>
<span style="color: #777777;">Layer Git repository (branch) Subdirectory</span>
<span style="color: #777777;">=============================================================================================================================</span>
<span style="color: #777777;">local:HEAD:openembedded-core git://git.yoctoproject.org/poky (master) meta</span>
<span style="color: #777777;"> required by: meta-python meta-oe</span>
<span style="color: #777777;">layers.openembedded.org:master:meta-oe git://git.openembedded.org/meta-openembedded (master) meta-oe</span>
<span style="color: #777777;"> required by: meta-python</span>
<span style="color: #777777;">layers.openembedded.org:master:meta-python git://git.openembedded.org/meta-openembedded (master) meta-python</span>
<span style="color: #777777;">Cloning into '/opt/oe/configs/z/build-master/6951/automation-hat/poky/layers/poky/meta-openembedded'...</span>
<span style="color: #777777;">remote: Counting objects: 141039, done.</span>
<span style="color: #777777;">remote: Compressing objects: 100% (46829/46829), done.</span>
<span style="color: #777777;">remote: Total 141039 (delta 88137), reused 140214 (delta 87626)</span>
<span style="color: #777777;">Receiving objects: 100% (141039/141039), 37.93 MiB | 297.00 KiB/s, done.</span>
<span style="color: #777777;">Resolving deltas: 100% (88137/88137), done.</span>
<span style="color: #777777;">Updating files: 100% (5664/5664), done.</span>
<span style="color: #777777;">Adding layer "meta-oe" (/opt/oe/configs/z/build-master/6951/automation-hat/poky/layers/poky/meta-openembedded/meta-oe) to conf/bblayers.conf</span>
<span style="color: #777777;">Adding layer "meta-python" (/opt/oe/configs/z/build-master/6951/automation-hat/poky/layers/poky/meta-openembedded/meta-python) to conf/bblayers.conf</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">I'm not overly fond of where it placed the downloads, but the nice thing is that it took care of the dependency (<span style="font-family: courier; font-size: x-small;">meta-python</span> depends on <span style="font-family: courier; font-size: x-small;">meta-oe</span>) and it updated my <span style="font-family: courier; font-size: x-small;">conf/bblayers.conf</span> file automatically for me.</p><p style="text-align: left;">Similarly to how we enabled the UART a while back, we have to explicitly tell the RaspberryPi that we want to enable i2c by setting the <span style="font-family: courier; font-size: x-small;">ENABLE_I2C</span> to 1. <i><b>NOTE</b></i>: this is specific to the RaspberryPi due to the way its hardware was designed; having to explicitly enable a UART or i2c is not an OpenEmbedded thing or a thing in general. This only applies to the <span style="font-family: courier; font-size: x-small;">ENABLE_I2C</span><span style="font-family: courier; font-size: small;"> </span>setting, the other tweaks are common OpenEmbedded idioms.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DL_DIR = "/opt/Downloads"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">ENABLE_UART = "1"</span>
<span style="color: #2db5b5;">ENABLE_I2C</span> = <span style="color: #bf7f0f;">"1"</span>
<span style="color: #2db5b5;">KERNEL_MODULE_AUTOLOAD</span> += <span style="color: #bf7f0f;">"i2c-dev"</span>
<span style="color: #777777;">CORE_IMAGE_EXTRA_INSTALL += " \</span>
<span style="color: #777777;"> ${MACHINE_EXTRA_RRECOMMENDS} \</span>
<span style="color: #777777;"> wpa-supplicant \</span>
<span style="color: #bf7f0f;"> i2c-tools \</span>
<span style="color: #777777;"> "</span>
<span style="color: #777777;">PACKAGECONFIG_append_pn-gdb = " tui"</span>
<span style="color: #777777;">PACKAGECONFIG_append_pn-gdb-cross-canadian-arm = " tui"</span>
<span style="color: #777777;">IMAGE_FSTYPES_append = " wic"</span>
<span style="color: #777777;">IMAGE_FSTYPES_remove = "wic.bz2 tar.bz2"</span>
<span style="color: #777777;">WARN_QA_append = " version-going-backwards"</span>
<span style="color: #777777;">ERROR_QA_remove = "version-going-backwards"</span>
<span style="color: #777777;">BB_DANGLINGAPPENDS_WARNONLY = "yes"</span>
<span style="color: #777777;">INHERIT += "buildhistory image-buildinfo buildstats-summary"</span>
<span style="color: #777777;">BUILDHISTORY_COMMIT = "1"</span>
<span style="color: #777777;">PACKAGE_CLASSES ?= "package_ipk"</span>
<span style="color: #777777;">SDKMACHINE = "x86_64"</span>
<span style="color: #777777;">EXTRA_IMAGE_FEATURES ?= "debug-tweaks"</span>
<span style="color: #777777;">USER_CLASSES ?= "buildstats image-mklibs image-prelink"</span>
<span style="color: #777777;">PATCHRESOLVE = "noop"</span>
<span style="color: #777777;">BB_DISKMON_DIRS ??= "\</span>
<span style="color: #777777;"> STOPTASKS,${TMPDIR},1G,100K \</span>
<span style="color: #777777;"> STOPTASKS,${DL_DIR},1G,100K \</span>
<span style="color: #777777;"> STOPTASKS,${SSTATE_DIR},1G,100K \</span>
<span style="color: #777777;"> STOPTASKS,/tmp,100M,100K \</span>
<span style="color: #777777;"> ABORT,${TMPDIR},100M,1K \</span>
<span style="color: #777777;"> ABORT,${DL_DIR},100M,1K \</span>
<span style="color: #777777;"> ABORT,${SSTATE_DIR},100M,1K \</span>
<span style="color: #777777;"> ABORT,/tmp,10M,1K"</span>
<span style="color: #777777;">PACKAGECONFIG_append_pn-qemu-system-native = " sdl"</span>
<span style="color: #777777;">CONF_VERSION = "1"</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Let's check to see if the new <i>python3-sn3218</i> recipe will build:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool build python3-sn3218
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% | | ETA: --:--:--</span>
<span style="color: #777777;">Loaded 0 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:16</span>
<span style="color: #777777;">Parsing of 2042 .bb files complete (0 cached, 2042 parsed). 3213 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:03</span>
<span style="color: #777777;">Loaded 3211 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2042 .bb files complete (2040 cached, 2 parsed). 3213 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">meta-oe </span>
<span style="color: #777777;">meta-python = "master:86a7820b7964ff91d7a26ac5c506e83292e347a3"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Found 0 Missed 0 Current 190 (0% match, 100% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: python3-sn3218: compiling from external source tree /z/build-master/6951/automation-hat/poky/build/workspace/sources/python3-sn3218/library</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 727 tasks of which 719 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 2 seconds</span>
<span style="color: #777777;">NOTE: Build completion summary:</span>
<span style="color: #777777;">NOTE: do_populate_sysroot: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_deploy_source_date_epoch: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_package: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_packagedata: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Success!</p><p style="text-align: left;">How about <i>automation-hat</i>?</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool build automation-hat
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 3211 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2042 .bb files complete (2040 cached, 2 parsed). 3213 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:03</span>
<span style="color: #777777;">Loaded 3211 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2042 .bb files complete (2040 cached, 2 parsed). 3213 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">meta-oe </span>
<span style="color: #777777;">meta-python = "master:86a7820b7964ff91d7a26ac5c506e83292e347a3"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:01</span>
<span style="color: #777777;">Sstate summary: Wanted 0 Found 0 Missed 0 Current 190 (0% match, 100% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: automation-hat: compiling from external source tree /z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat/library</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+git999-r0 do_packagedata: QA Issue: Package version for package automation-hat-src went backwards which would break package feeds (from 0:1.0+git999-r0 to 0:0.2.3+git999-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+git999-r0 do_packagedata: QA Issue: Package version for package automation-hat-dbg went backwards which would break package feeds (from 0:1.0+git999-r0 to 0:0.2.3+git999-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+git999-r0 do_packagedata: QA Issue: Package version for package automation-hat-staticdev went backwards which would break package feeds (from 0:1.0+git999-r0 to 0:0.2.3+git999-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+git999-r0 do_packagedata: QA Issue: Package version for package automation-hat-dev went backwards which would break package feeds (from 0:1.0+git999-r0 to 0:0.2.3+git999-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+git999-r0 do_packagedata: QA Issue: Package version for package automation-hat-doc went backwards which would break package feeds (from 0:1.0+git999-r0 to 0:0.2.3+git999-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+git999-r0 do_packagedata: QA Issue: Package version for package automation-hat-locale went backwards which would break package feeds (from 0:1.0+git999-r0 to 0:0.2.3+git999-r0) [version-going-backwards]</span>
<span style="color: #777777;">WARNING: automation-hat-0.2.3+git999-r0 do_packagedata: QA Issue: Package version for package automation-hat went backwards which would break package feeds (from 0:1.0+git999-r0 to 0:0.2.3+git999-r0) [version-going-backwards]</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 727 tasks of which 719 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 1 seconds</span>
<span style="color: #777777;">NOTE: Build completion summary:</span>
<span style="color: #777777;">NOTE: do_populate_sysroot: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_deploy_source_date_epoch: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_package: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">NOTE: do_packagedata: 0.0% sstate reuse(0 setscene, 1 scratch)</span>
<span style="color: #777777;">Summary: There were 7 WARNING messages shown.</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Looking good!</p><p style="text-align: left;">Due to the fact we're adding these two new packages, plus both these packages have a runtime dependency on python3, plus we're adding i2c things and we want the i2c kernel module inserted at boot, it's probably time to build and flash a whole new image.</p><p style="text-align: left;">We could do the usual <span style="font-family: courier; font-size: x-small;">bitbake core-image-full-cmdline</span> here, however if we do <span style="font-family: courier; font-size: x-small;">devtool build-image</span> instead we'll find that devtool will add the recipes from our workspace (and their dependencies) into the resulting image, which is probably what we want.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> devtool build-image core-image-full-cmdline
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 3211 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2042 .bb files complete (2040 cached, 2 parsed). 3213 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">INFO: Building image core-image-full-cmdline with the following additional packages: automation-hat python3-sn3218</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:03</span>
<span style="color: #777777;">Loaded 3211 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2042 .bb files complete (2039 cached, 3 parsed). 3213 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">NOTE: Resolving any missing task queue dependencies</span>
<span style="color: #777777;">Build Configuration:</span>
<span style="color: #777777;">BB_VERSION = "1.47.0"</span>
<span style="color: #777777;">BUILD_SYS = "x86_64-linux"</span>
<span style="color: #777777;">NATIVELSBSTRING = "universal"</span>
<span style="color: #777777;">TARGET_SYS = "aarch64-poky-linux"</span>
<span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">DISTRO_VERSION = "3.1+snapshot-20201018"</span>
<span style="color: #777777;">TUNE_FEATURES = "aarch64 armv8a crc cortexa53"</span>
<span style="color: #777777;">TARGET_FPU = ""</span>
<span style="color: #777777;">meta </span>
<span style="color: #777777;">meta-poky </span>
<span style="color: #777777;">meta-yocto-bsp = "master:7cad26d585f67fa6bf873b8be361c6335a7db376"</span>
<span style="color: #777777;">meta-raspberrypi = "master:6f85611576b7ccbfb6012631f741bd1daeffc9c9"</span>
<span style="color: #777777;">workspace = "master:b1a0414a6df77674a860c365825a4500e6cd698b"</span>
<span style="color: #777777;">meta-oe </span>
<span style="color: #777777;">meta-python = "master:86a7820b7964ff91d7a26ac5c506e83292e347a3"</span>
<span style="color: #777777;">Initialising tasks: 100% |######################################################################################################################################################################| Time: 0:00:07</span>
<span style="color: #777777;">Sstate summary: Wanted 35 Found 0 Missed 35 Current 1508 (0% match, 97% complete)</span>
<span style="color: #777777;">NOTE: Executing Tasks</span>
<span style="color: #777777;">NOTE: python3-sn3218: compiling from external source tree /z/build-master/6951/automation-hat/poky/build/workspace/sources/python3-sn3218/library</span>
<span style="color: #777777;">NOTE: automation-hat: compiling from external source tree /z/build-master/6951/automation-hat/poky/build/workspace/sources/automation-hat/library</span>
<span style="color: #777777;">NOTE: Tasks Summary: Attempted 3998 tasks of which 3828 didn't need to be rerun and all succeeded.</span>
<span style="color: #777777;">NOTE: Writing buildhistory</span>
<span style="color: #777777;">NOTE: Writing buildhistory took: 1 seconds</span>
<span style="color: #777777;">NOTE: Build completion summary:</span>
<span style="color: #777777;">NOTE: do_populate_sysroot: 0.0% sstate reuse(0 setscene, 5 scratch)</span>
<span style="color: #777777;">NOTE: do_deploy_source_date_epoch: 0.0% sstate reuse(0 setscene, 4 scratch)</span>
<span style="color: #777777;">NOTE: do_package_qa: 0.0% sstate reuse(0 setscene, 7 scratch)</span>
<span style="color: #777777;">NOTE: do_package: 0.0% sstate reuse(0 setscene, 7 scratch)</span>
<span style="color: #777777;">NOTE: do_packagedata: 0.0% sstate reuse(0 setscene, 7 scratch)</span>
<span style="color: #777777;">NOTE: do_package_write_ipk: 0.0% sstate reuse(0 setscene, 7 scratch)</span>
<span style="color: #777777;">NOTE: do_populate_lic: 0.0% sstate reuse(0 setscene, 5 scratch)</span>
<span style="color: #777777;">INFO: Successfully built core-image-full-cmdline. You can find output files in /z/build-master/6951/automation-hat/poky/build/tmp/deploy/images/raspberrypi3-64</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;"><i style="font-weight: bold;">NOTE</i>: on line 9 the build tells you that it is installing our two new packages into the image.</p><p style="text-align: left;">Flash this image to your µSD card, insert the card into the target, and apply power. After logging in:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;">1
2
3
4
5
6
7</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">root@raspberrypi3-64:~#</span> python3
<span style="color: #777777;">Python 3.8.5 (default, Jul 20 2020, 13:26:22) </span>
<span style="color: #777777;">[GCC 10.2.0] on linux</span>
<span style="color: #777777;">Type "help", "copyright", "credits" or "license" for more information.</span>
<span style="color: #348c00;">>>></span> import automationhat
<span style="color: #348c00;">>>></span> automationhat.output.one.on()
<span style="color: #348c00;">>>></span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">Looking at the target:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-9AMKCJKqzUQ/X3uW8td_qwI/AAAAAAAAiaI/v7m7Ewj4DVI2o_NDb4zV4UjysMbo7Sw2wCLcBGAsYHQ/s640/IMG_4137.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" src="https://1.bp.blogspot.com/-9AMKCJKqzUQ/X3uW8td_qwI/AAAAAAAAiaI/v7m7Ewj4DVI2o_NDb4zV4UjysMbo7Sw2wCLcBGAsYHQ/s320/IMG_4137.JPG" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-zYXXXLhbGSk/X3uXoJdIrzI/AAAAAAAAiaQ/thROjiAjxZ8iGE9C7dd_77hW_cCXgOanwCLcBGAsYHQ/s640/IMG_4138.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" src="https://1.bp.blogspot.com/-zYXXXLhbGSk/X3uXoJdIrzI/AAAAAAAAiaQ/thROjiAjxZ8iGE9C7dd_77hW_cCXgOanwCLcBGAsYHQ/s320/IMG_4138.JPG" width="320" /></a></div>
<p style="text-align: left;">Success!</p><h2 style="text-align: left;">Finishing Up</h2><p style="text-align: left;">We used <i>devtool</i> to help us create two recipes. Those recipes (and their sources) are still in our "workspace". We need to finish working with them and put them somewhere. But where? The layers we're using aren't under our control. We need to create our own layer so we have a place to store these new recipes.</p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #348c00;">$</span> bitbake-layers create-layer ../layers/devtool-additions
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">Add your new layer with 'bitbake-layers add-layer ../layers/devtool-additions'</span>
<span style="color: #348c00;">$</span> bitbake-layers add-layer ../layers/devtool-additions/
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #348c00;">$</span> devtool finish -f -r automation-hat ../layers/devtool-additions/
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">WARNING: Source tree is not clean, continuing as requested by -f/--force</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% | | ETA: --:--:--</span>
<span style="color: #777777;">Loaded 0 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:14</span>
<span style="color: #777777;">Parsing of 2043 .bb files complete (0 cached, 2043 parsed). 3214 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">INFO: Updating SRCREV in recipe automation-hat_git.bb</span>
<span style="color: #777777;">INFO: Moving recipe file to /z/build-master/6951/automation-hat/poky/layers/devtool-additions/recipes-automation-hat/automation-hat</span>
<span style="color: #777777;">INFO: -r argument used on automation-hat, removing source tree. You will lose any unsaved work</span>
<span style="color: #348c00;">$</span> devtool finish -f -r python3-sn3218 ../layers/devtool-additions/
<span style="color: #777777;">NOTE: Starting bitbake server...</span>
<span style="color: #777777;">WARNING: Source tree is not clean, continuing as requested by -f/--force</span>
<span style="color: #777777;">NOTE: Reconnecting to bitbake server...</span>
<span style="color: #777777;">NOTE: Retrying server connection (#1)...</span>
<span style="color: #777777;">Loading cache: 100% |###########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Loaded 3212 entries from dependency cache.</span>
<span style="color: #777777;">Parsing recipes: 100% |#########################################################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Parsing of 2043 .bb files complete (2041 cached, 2 parsed). 3214 targets, 123 skipped, 0 masked, 0 errors.</span>
<span style="color: #777777;">Removing 1 recipes from the cortexa53 sysroot: 100% |###########################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">Removing 1 recipes from the raspberrypi3_64 sysroot: 100% |#####################################################################################################################################| Time: 0:00:00</span>
<span style="color: #777777;">INFO: Updating SRCREV in recipe python3-sn3218_git.bb</span>
<span style="color: #777777;">INFO: Moving recipe file to /z/build-master/6951/automation-hat/poky/layers/devtool-additions/recipes-python3-sn3218/python3-sn3218</span>
<span style="color: #777777;">INFO: -r argument used on python3-sn3218, removing source tree. You will lose any unsaved work</span>
<span style="color: #348c00;">$</span> rm -fr workspace/sources/
<span style="color: #348c00;">$</span> tree ../layers/devtool-additions/
<span style="color: #777777;">../layers/devtool-additions/</span>
<span style="color: #777777;">├── COPYING.MIT</span>
<span style="color: #777777;">├── README</span>
<span style="color: #777777;">├── conf</span>
<span style="color: #777777;">│ └── layer.conf</span>
<span style="color: #777777;">├── recipes-automation-hat</span>
<span style="color: #777777;">│ └── automation-hat</span>
<span style="color: #777777;">│ └── automation-hat_git.bb</span>
<span style="color: #777777;">├── recipes-example</span>
<span style="color: #777777;">│ └── example</span>
<span style="color: #777777;">│ └── example_0.1.bb</span>
<span style="color: #777777;">└── recipes-python3-sn3218</span>
<span style="color: #777777;"> └── python3-sn3218</span>
<span style="color: #777777;"> └── python3-sn3218_git.bb</span>
<span style="color: #777777;">7 directories, 6 files</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;">This looks good. The "example" boilerplate can be removed from the layer.</p><p style="text-align: left;"><i style="font-weight: bold;">NOTE</i>: if you want to build an image, you have to go back to using <i>bitbake</i> and you have to explicitly add the package(s) to your image. Thanks to dependencies, the only package that needs to be added to an image is <i>automation-hat</i></p>
<!--HTML generated using hilite.me--><div style="background: rgb(217, 201, 163) none repeat scroll 0% 0%; border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: medium solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41</pre></td><td><pre style="color: #4a364d; line-height: 125%; margin: 5px;"><span></span><span style="color: #777777;">MACHINE = "raspberrypi3-64"</span>
<span style="color: #777777;">DL_DIR = "/opt/Downloads"</span>
<span style="color: #777777;">DISTRO = "poky"</span>
<span style="color: #777777;">ENABLE_UART = "1"</span>
<span style="color: #777777;">ENABLE_I2C = "1"</span>
<span style="color: #777777;">KERNEL_MODULE_AUTOLOAD += "i2c-dev"</span>
<span style="color: #777777;">CORE_IMAGE_EXTRA_INSTALL += " \</span>
<span style="color: #777777;"> ${MACHINE_EXTRA_RRECOMMENDS} \</span>
<span style="color: #777777;"> wpa-supplicant \</span>
<span style="color: #777777;"> i2c-tools \</span>
<span style="color: #bf7f0f;"> automation-hat \</span>
<span style="color: #777777;"> "</span>
<span style="color: #777777;">PACKAGECONFIG_append_pn-gdb = " tui"</span>
<span style="color: #777777;">PACKAGECONFIG_append_pn-gdb-cross-canadian-arm = " tui"</span>
<span style="color: #777777;">IMAGE_FSTYPES_append = " wic"</span>
<span style="color: #777777;">IMAGE_FSTYPES_remove = "wic.bz2 tar.bz2"</span>
<span style="color: #777777;">WARN_QA_append = " version-going-backwards"</span>
<span style="color: #777777;">ERROR_QA_remove = "version-going-backwards"</span>
<span style="color: #777777;">BB_DANGLINGAPPENDS_WARNONLY = "yes"</span>
<span style="color: #777777;">INHERIT += "buildhistory image-buildinfo buildstats-summary"</span>
<span style="color: #777777;">BUILDHISTORY_COMMIT = "1"</span>
<span style="color: #777777;">PACKAGE_CLASSES ?= "package_ipk"</span>
<span style="color: #777777;">SDKMACHINE = "x86_64"</span>
<span style="color: #777777;">EXTRA_IMAGE_FEATURES ?= "debug-tweaks"</span>
<span style="color: #777777;">USER_CLASSES ?= "buildstats image-mklibs image-prelink"</span>
<span style="color: #777777;">PATCHRESOLVE = "noop"</span>
<span style="color: #777777;">BB_DISKMON_DIRS ??= "\</span>
<span style="color: #777777;"> STOPTASKS,${TMPDIR},1G,100K \</span>
<span style="color: #777777;"> STOPTASKS,${DL_DIR},1G,100K \</span>
<span style="color: #777777;"> STOPTASKS,${SSTATE_DIR},1G,100K \</span>
<span style="color: #777777;"> STOPTASKS,/tmp,100M,100K \</span>
<span style="color: #777777;"> ABORT,${TMPDIR},100M,1K \</span>
<span style="color: #777777;"> ABORT,${DL_DIR},100M,1K \</span>
<span style="color: #777777;"> ABORT,${SSTATE_DIR},100M,1K \</span>
<span style="color: #777777;"> ABORT,/tmp,10M,1K"</span>
<span style="color: #777777;">PACKAGECONFIG_append_pn-qemu-system-native = " sdl"</span>
<span style="color: #777777;">CONF_VERSION = "1"</span>
</pre></td></tr></tbody></table></div>
<p style="text-align: left;"><br /></p>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-47031825911099848852020-06-09T08:53:00.002-04:002022-03-21T08:43:31.821-04:00NAND Flash Basics<h2>
Introduction </h2>
NAND flash is a type of non-volatile data storage technology, and is often used on embedded devices much the same way a hard-drive would be used on a desktop machine.<br />
<br />
NAND flash is built on <i>cells</i>. The
original flash devices stored one bit of information per cell, and were called single-level cell (SLC)
technology. Later two bits were stored per cell, so this became (unfortunately
named) multi-level cell (MLC) technology. When the technology
came along to store three bits per cell, it was named triple-level cell
(TLC) technology. As you can see: "single" means one, "multiple" means two, and "triple" means three. According to <a href="https://en.wikipedia.org/wiki/Multi-level_cell">wikipedia</a> there now exist (or are in development) quad- devices with 4 bits per cell (QLC) and penta- (PLC) devices with 5. <br />
<br />
Unlike traditional hard-drives (i.e. built on spinning platters), the individual cells used to store bits in NAND flash can not be twiddled indefinitely. New or newly-erased flash shows up as all bits set to 1. The act of writing
data to a freshly erased NAND device is simply the process of changing the necessary bits from 1s to 0s. The moment the data you want to write needs to flip a 0 back
to a 1, an <i>erase</i> cycle is needed. If, coincidentally, every
time you needed to write data to a NAND all that was required was to
flip bits from 1s to 0s, you would never need to perform an erase cycle. Flipping bits from 1s to 0s comes "for free", but erasing bits from 0s to 1s comes at a cost. Each time a bit is switched from a 0 to a 1 (i.e. erased) <a href="https://www.ni.com/en-ca/support/documentation/supplemental/12/understanding-life-expectancy-of-flash-storage.html">the oxide layer of the cell is degraded</a>. Over time it will stop being possible to erase a cell.<br />
<br />
Every
device comes with a claim of being able to support a given minimum
number of program/erase (P/E) cycles, but the maximum number is never known.
In general SLC NAND supports a higher number of P/E cycles than MLC, and
MLC supports more P/E cycles than TLC. In general the drop-off in P/E
endurance between the different technologies is quite significant; on
the order of magnitudes. You'll have to consult the datasheets for
specific devices for the actual performance of any specific device, but
in general SLC devices are good for ~50,000 to 100,000 P/E cycles, MLC
~1,000 to 10,000, and TLC under ~1,000 P/E cycles. <br />
<br />
Internally, cells are combined to form bytes, bytes are combined to form
pages, pages are gathered into blocks, and blocks are combined to form
planes.<br />
<br />
From outside a NAND device one can only access
the data inside a NAND device one page at a time. If you want to read
one byte of data, the entire page on which that byte is stored must be
retrieved, then the specific byte of interest can be accessed. The same
is true for writing; you can only write data to a NAND device one page
at a time. More recent devices will
often break a single page up into fixed, equal-sized sub-pages which can
help when fetching or writing data. Erasing, however, needs to be
performed a
whole block at a time. Fancy devices can allow pages in separate planes
to be read or written simultaneously. In general pages are for
reading/writing, blocks for erasing, and operations can occur
simultaneously to separate planes. You'll need to consult the datasheet
of any
specific device for each device's specific behaviour.<br />
<br />
The sizes of pages, blocks, and planes on a NAND device varies by device. A typical device will
have page sizes in the 2048-bytes/page range, will split a page into 4 sub-pages, will combine around 64 pages to form a block, and use roughly 1024 blocks for each plane. <br />
<br />
Although storing more bits per cell improves storage density, there are
trade-offs such as: slower access times, and reduced life expectancy of the
device. So while TLC is newer than MLC and has some advantages over it,
TLC doesn't displace MLC; MLC is still available. The same holds true
for SLC; even though it is "older" technology, it is faster and has an
order of magnitude or better P/E cycles over "newer" technology. Therefore SLC is still used quite extensively when the circumstances call for improved reliability or speed over size or cost. As you would expect SLC flash is the most expensive, with the price dropping with each increase in bits per cell.<br />
<br />
<h2>
ECC and OOB</h2>
<br />
In order to combat the strange situation of a device that will (by design) fail over time, in practice ECC checks are often calculated for the data that is stored on the device. In fact if you read the fine print in the datasheet regarding a device's P/E endurance you'll often find that these endurance claims are based on the expectation that ECC is being used. But if you're going to calculate an ECC for a chunk of data, where will you store this value? There's not much point to generating an ECC for a chunk of data if it isn't stored with the data so it can be checked later on. As such, each NAND flash device comes with extra storage space added to the device<i> </i>in order to store these ECC calculations (or any other book-keeping data you'd like to track). So if you buy (for example) a 512MB-sized NAND flash device, you might be given a device that has 512MB+8MB of storage. This extra area is referred to as the <i>out of bounds</i> or <i>OOB</i> area.<br />
<br />
Typically ECCs are calculated per page of NAND data. When you ask a device for a page of data (the smallest size of data you can request from a NAND device) in addition to receiving that page worth of data you will also be given the data from that page's OOB area. The same is true for writing: when you want to write data to a NAND device, for each page you give it, you also have to provide the data for that page's OOB area.<br />
<br />
By the way the answer is "yes it is" (if you're wondering whether or not the OOB area is susceptible to the same degradation as the rest of the data on a NAND device). One could add OOB areas to OOB areas <i>ad infinitum</i>, but one level is considered sufficient. A failure in either of the main data area or an OOB area is a failure for that page+OOB combination.<br />
<br />
<h2>
Raw vs FTL</h2>
Getting the most out of your NAND device requires not just ECC checks, but the ability to mark pages as bad, support for caching, tolerance for sudden power loss, wear-levelling, and other techniques that help it perform optimally and correctly. The addition of these algorithms is so necessary that many devices that use NAND flash internally will put a microcontroller and code between the user and the memory. These are called <i>FTL</i> or <i>managed</i> devices.<br />
<br />
<i>FTL</i> stands for <i>flash translation layer</i> and it forms a level of indirection between what the user requests, and what actually happens to the memory. For example, the user might continuously read/modify/update one specific page over and over. But knowing that hammering on only one page might cause that page to wear out much faster than the rest of the device, internally the FTL actually maps the requests for modifications to a specific page that the user is commanding, to modifying a different physical page with every request. This lets the user think they are reading and writing the same page over and over while in fact those requests are being spread over the entire device so as to not wear out any one part of the chip prematurely. This called wear-levelling.<br />
<br />
Managed devices will often present a different interface to the outside world than what one would expect from raw NAND. Therefore when working with a device that uses NAND technology, it's important to know whether you're dealing with a raw NAND chip, or one that is managed.<br />
<br />
Most managed devices present themselves as hard-drives, so using them under Linux is simply a matter of having Linux treat the device the same as it would any other hard-drive. Once Linux is interfaced to it, you simply use it as any other hard-drive: you partition it, format with your favourite filesystem, mount it, then use it like normal.<br />
<br />
If you're using a raw NAND device, then your best bet is to make use of raw NAND-handling software that is already available in order to deal with NAND's quirks. Under Linux, the MTD subsystem provides a uniform, though raw, interface to NAND. On top of the MTD subsystem you could use JFFS2, but it has been mostly superseded by UBI and UBIFS.<br />
<br />
Unlike JFFS2, UBIFS can't sit directly on top of the MTD subsystem. It needs to sit inside a UBI container. It is UBI that has all the fancy logic and algorithms for managing the physical memory, providing fast boot times, handling power interruptions, wear-levelling, and so forth. UBIFS is a NAND-aware filesystem that sits on top of UBI with which it works well. A UBI can contain one or more UBIFS filesystems.<br />
<br />
<h2>
External Interface and ONFI</h2>
Interacting with NAND has been simplified and standardized thanks to the efforts of <a href="http://www.onfi.org/">ONFI</a>, the Open NAND Flash Interface. All NAND devices have either an 8- or 16-bit parallel I/O bus, plus a number of standardized control lines. Telling the NAND device what you want to do is simply a matter of some combination of giving it a command, providing it with an "address", then reading or writing the data. The I/O bus is multiplexed between commands, "addresses", and data. The NAND device distinguishes between these pieces of information based on the cycle and on the values of the logic levels on the control lines.<br />
<br />
I use "address" in quotes because the address of any piece of data in a NAND device is not referenced the same way a piece of data would be referenced in, for example, RAM. As I've mentioned a couple times, you can only interface with a NAND device one page at a time. Telling the NAND device which page you want is a matter of specifying its column, its page address within a block, its block number, and specifying which plane it's on. The bits specifying this information are jumbled up together and sent to the device as either 3, 4, or 5 (depends on the device) 8-bit words (regardless whether the device has an 8- or 16-bit I/O interface) which are sent in subsequent I/O cycles during the "address" phase.<br />
<br />
ONFI also specifies the bit patterns of the various commands that can be issued to a NAND device. In this way Linux's MTD software (for example) doesn't need to be chip-specific with regards to the command definitions.<br />
<br />
<h2>
Timing Charts</h2><div>
Like most pieces of silicon, NAND devices don't operate infinitely quickly; they certainly don't operate at the speed of the bus connecting your SoC to the NAND device. As such, one of the most important pieces of information contained in your device's datasheet is the table specifying minimum or maximum timings of various operations.</div><div><br /></div><div>This table is usually found in a section called "AC Characteristics" and includes the timing information for around 3 dozen or so parameters. For example, the Address Latch Enable setup time is given as t<sub>ALS</sub>. Sometimes the timing is specified as a minimum amount of time that one needs to wait for an event, other times it specifies a maximum time. Each parameter has an associated unit, usually nano-seconds, but sometimes micro-seconds.</div><div><br /></div><div>Some parts of a NAND's datasheet aren't as important as others from a software point of view. But when working with a NAND chip at a low level, the timing information is certainly one of the more important sections.<br /></div>
<br />
<h2>
SoCs and NAND Controllers</h2><div>
It would be pretty rare to see a micro-controller connected to a NAND device directly using nothing but GPIO lines. Part of the difficulty in controlling a NAND device directly would be to get the timing right and efficient. As such most SoCs include a dedicated NAND Controller.</div><div><br /></div><div>The job of the NAND Controller is to handle the interaction between the SoC and the NAND so that the SoC is freed from the lowest-level details of handling the NAND; like a sort of buffer. The SoC creates a request by loading the controller's registers with the correct values, and it's the controller's job to twiddle the various control and I/O lines in the correct sequence, at the right times.</div><div><br /></div><div>An SoC's NAND Controller will often incorporate logic for handling ECC calculations and manipulating portions of the OOB areas as appropriate. For example, I mentioned earlier that when providing data to the NAND, one must also supply the OOB area. In some cases the software only needs to provide the data, and the controller will calculate the ECC and supply the OOB data to the NAND device itself. The reverse also applies when reading data: the controller can be instructed to check the ECC and it will either correct the data itself (if it can, if an error is detected) or set flags to let the user know an issue was found (or both). In which case the user simply receives a page of corrected data.</div><div><br /></div><div>The NAND Controller can only do its job properly if it is configured properly. For each SoC that has a NAND Controller, a portion of its registers need to be used to give the user a place to specify the configuration and timing parameters of the specific NAND device being used.</div><div><br /></div><div>Configuration usually involves telling the NAND Controller the bus width (8 or 16), the page size, whether or not sub-pages are used, how many bytes to use when specifying the "address" (3, 4, or 5), and various other things.<br /></div><div><br /></div><div>For timing, the datasheet for the NAND device will always specify timing in absolute, "wall clock" values (e.g. 25[ns]), whereas the NAND Controller only knows how to count clock ticks. Therefore not only do you need to know the clock rate of the bus to which the NAND device is connected (which is almost guaranteed to not be the same as the clock rate of the CPU itself), but these values will need to be adjusted anytime the clock rate changes (e.g. in low power or power-saving modes). Telling the controller how many clock ticks to wait will always be specified as an integer number. Knowing your clock rate, you'll need to figure out how many ticks are required to get at least that much delay, then round up. For example a given timing parameter might specify a minimum delay of 25[ns], at a clock rate of 130[MHz] this would translate to 3.25 clocks. But since the controller can't count a quarter of a clock, this value needs to be rounded up to 4. At this clock rate 4 clocks actually gives a delay of 30.7[ns], but we can't specify 3 otherwise the controller won't wait long enough for the NAND device, and errors will result.</div><div><br /></div><div>Unfortunately it's rare to find a controller that has a 1:1 mapping
between the timing parameters provided in the NAND device's datasheet
and the timing parameters required by the NAND Controller. For reasons that can only be described as masochistic, the NAND Controller will almost always want timing values that are calculations that, if you're lucky, will be based on values found in the NAND device's datasheet. For example, a typical device's datasheet will (thankfully) provide a timing parameter called t<sub>RHZ</sub>. But instead of asking for this value, the NAND Controller might say: I need NAND_TA and you calculate NAND_TA as:</div><div><br /></div><blockquote><div>((RD_HIGH - RD_LOW)/HCLK) + (NAND_TA/HCLK) ≥ t<sub>RHZ</sub></div></blockquote><div><br /></div><div>RD_HIGH and RD_LOW are other timing parameters the controller wants, which you've already calculated in a manner similar to the above, but you must re-arrange the inequality to isolate NAND_TA. Thankfully t<sub>RHZ</sub> is found in the datasheet; sometimes the controller will request a parameter that isn't in the datasheet and you're left trying to figure out how to use the parameters the datasheet gives you to determine the value the controller wants.</div><div><br /></div><div>Also, the above calculations depend on your ability to figure out the clock rate which requires an understanding of the clocking and PLL mechanisms of your SoC, which isn't trivial either.</div><div><br /></div><div><h2 style="text-align: left;">Conclusion</h2><div>NAND flash is an interesting technology, with its own advantages and quirks. To get NAND working on a specific device requires an understanding of the details of the specific NAND device you're using, as well as understanding the capabilities and limitations of your SoC.<br /></div></div>TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-6378120897488309672020-04-28T18:08:00.001-04:002022-03-21T08:43:26.617-04:00The LPC32xx Project - introductionFor the last while I've been working on an extremely exciting project at work; certainly one of the best jobs to come my way. I've been lucky in my career to have worked on some really exciting things, and this project is certainly one of them.<br />
<br />
We have a customer who has a range of hardware from some very old stuff to some very new stuff. They want the same versions of bootloader, kernel, and userspace running on all of them. Additionally they want, for each device, A/B updates, each of which is to run in its own container, and all built with OpenEmbedded/Yocto.<br />
<br />
I'm not at all worried about finding support for the newish stuff. It's actually the oldest hardware that needs the most attention. For example, look at the mailing lists for the Linux kernel, U-Boot, or anything graphics-related and you'll find hundreds of patches from many developers every day all working on hardware so cutting edge, some of it isn't even available for purchase yet. But many fewer people are making sure the old stuff is still working. At best a developer will make sure their changes won't cause support for an older device to stop compiling, but sometimes that's not enough.<br />
<br />
Earlier in my career I had an opportunity to do board bring-up. The company I was working for had just created their own custom board. It was based around a variant of the AMCC PowerPC 440 SoC. Our board, thankfully, was very closely modelled on the reference board for the specific SoC we were using, but with two key differences:<br />
<ol>
<li>we were using a brand of SDRAM that differed from the one on the reference board (and therefore the timing parameters needed tweaking), and</li>
<li>whereas the reference board was running at a middle-of-the-road clocking, we wanted to run our board at the highest clock rate possible</li>
</ol>
Although upstream U-Boot already had support for the reference board, it was my job to update it to work on our board by completing these two tasks. Before starting this job, I hadn't even heard the phrase "board bring-up", but I was hooked! If I could have, I would have plotted a career from that time on that would have included a lot more board bring-up activities! But you take what you can get, and there are <i>some</i> other exciting things to do other than board bring-up.<br />
<br />
What I enjoy most about board bring-up is it provides an opportunity to
get deep down into the details of how an SoC works. We're all aware of
SDRAM, and flash, and DMA, and all of the dozens of other pieces that
fit together to make an SoC. But it's not every day one gets the
opportunity to examine these things <i>at the register level</i>. Getting these two tasks working was very exciting for me; definitely a highlight.<br />
<br />
Here I am, years later, and I find myself doing board bring-up again. However this time it's not with cutting-edge hardware, but rather with really old hardware: the NXP LPC32xx SoC. I realize it's strange for me to claim to be doing "board bring-up" for an SoC that clearly already has support in U-Boot and the Linux kernel. However the fact is the support for this device was added decades ago and (especially in the case of U-Boot) has bitrotted quite badly in the interim.<br />
<br />
U-Boot is a very current and exciting project! It's not unusual for the daily patch count to run well into the hundreds. There are always new boards and SoCs in need of support, plus there are ongoing projects to improve the underlying structure of the code, its build system, and its test/ci infrastructure. With a code base moving this fast, an older device can quickly fall out of step with the rest of the project.<br />
<br />
I've been busily working on this project for a while and enjoying every minute. I'll be blogging more about it!TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-2197558128602634182019-10-21T15:47:00.001-04:002022-03-21T08:43:21.302-04:00OE Floating-Point Options for ARMv5 (ARM926EJ-S)One of the (many) things I enjoy about OpenEmbedded is how easy it is to try out different configurations. Want to switch from <i>sysvinit</i> to <i>systemd</i>? Change the config, re-build, and there's your new image to test. Want to switch from <i>busybox</i> to <i>coreutils</i>? Change the config, re-build, and there's your new image.<br />
<br />
Recently, I have been working with an ARMv5 device that was released in 2008: the NXP LPC3240 which is based on the ARM926EJ-S SoC. The specific device I'm using has a <a href="https://en.wikipedia.org/wiki/ARM_architecture#VFP" target="_blank">VFPv2</a> unit, however since the VFP was optional on the ARM926EJ-S, most distros/images are built with no floating-point support. From the standpoint of binary distributions, this makes the most sense: if you want to supply a binary to run on the most number of devices, build for the lowest common denominator. But when building your own distro/images from source using OpenEmbedded, you have the flexibility to tweak the parameters of your build to suit the specifics of your hardware.<br />
<br />
Nowadays, a user has 3 choices when it comes to VFP on the ARM926EJ-S:<br />
<ol>
<li><i>soft</i>: floating-point emulated in software (no hardware floating-point)</li>
<li><i>softfp</i>: enable hardware floating-point but have floating-point parameters passed in integer registers (i.e. use the <i>soft</i> calling conventions)</li>
<li><i>hard</i>: enable floating-point and have floating-point parameters passed in floating-point registers (i.e. use FPU-specific calling conventions)</li>
</ol>
The naming of option 2 (<i>softfp</i>) is unfortunate. To me, saying "<i>soft floating-point"</i> implies the floating-point is being emulated in software. However, its name was meant to contrast its calling convention with that of hard floating-point, not to imply the floating-point is being emulated in software.<br />
<br />
By default in OpenEmbedded, specifying <span style="font-family: "courier new" , "courier" , monospace;">tune-arm926ejs.inc</span> sets the <span style="font-family: "courier new" , "courier" , monospace;">DEFAULTTUNE</span> to "<span style="font-family: "courier new" , "courier" , monospace;">armv5te</span>" which disables VFP. By tweaking <span style="font-family: "courier new" , "courier" , monospace;">DEFAULTTUNE</span> in your <span style="font-family: "courier new" , "courier" , monospace;">machine.conf</span> file (or <span style="font-family: "courier new" , "courier" , monospace;">local.conf</span>) you can try out all the options. Personally, when setting <span style="font-family: "courier new" , "courier" , monospace;">DEFAULTTUNE</span>, I also like to tweak <span style="font-family: "courier new" , "courier" , monospace;">TUNE_CCARGS</span>.<br />
<br />
To try out the different options, set the following parameters:<br />
<ol>
<li><i>soft</i>:<br /><span style="font-family: "courier new" , "courier" , monospace;">DEFAULTTUNE = "armv5te"<br />TUNE_CCARGS = "-mcpu=arm926ej-s -marm"</span></li>
<li><i>softfp</i>:<br /><span style="font-family: "courier new" , "courier" , monospace;">DEFAULTTUNE = "armv5te-vfp"<br />TUNE_CCARGS = "-mcpu=arm926ej-s -mfpu=vfp -mfloat-abi=softfp -marm"</span></li>
<li><i>hard</i>:<br /><span style="font-family: "courier new" , "courier" , monospace;">DEFAULTTUNE = "armv5tehf-vfp"<br />TUNE_CCARGS = "-mcpu=arm926ej-s -mfpu=vfp -mfloat-abi=hard -marm"</span></li>
</ol>
The <i>meta-openembedded/meta-oe</i> layer provides <a href="http://cgit.openembedded.org/meta-openembedded/tree/meta-oe/recipes-benchmark" target="_blank">a number of recipes for benchmark applications</a>. Interesting performance benchmark programs include: <a href="http://cgit.openembedded.org/meta-openembedded/tree/meta-oe/recipes-benchmark/whetstone/whetstone_1.2.bb" target="_blank"><i>whetstone</i></a><i>, </i><a href="http://cgit.openembedded.org/meta-openembedded/tree/meta-oe/recipes-benchmark/dhrystone/dhrystone_2.1.bb" target="_blank">dhrystone</a>, <a href="http://cgit.openembedded.org/meta-openembedded/tree/meta-oe/recipes-benchmark/linpack/linpack_1.0.bb" target="_blank">linpack</a>, <a href="http://cgit.openembedded.org/meta-openembedded/tree/meta-oe/recipes-benchmark/nbench-byte/nbench-byte_2.2.3.bb" target="_blank">nbench</a>, and the "cpu" test of <a href="http://cgit.openembedded.org/meta-openembedded/tree/meta-oe/recipes-benchmark/sysbench/sysbench_0.4.12.bb" target="_blank">sysbench</a>.<br />
<br />
<blockquote class="tr_bq">
<i><b>STD BENCHMARK DISCLAIMER:</b></i> when it comes to benchmarks it's always important to remember that they are synthetic. That is: they are programs created to measure the performance of some <i>artificial</i> work-load of their choosing. If you want to know how the performance of <i>your</i> program will change under different settings, the only real way to determine that is to build and test <i>your</i> specific program under the different settings. It's also worth pointing out that during the era when benchmark programs were a really hot topic (late 90's-ish?) many vendors would tailor their hardware towards the popular benchmark programs of the time, skewing the results dramatically. In other words, a specific piece of hardware would be tuned to run a specific benchmark really well, but "real" workloads wouldn't see much improvement. Therefore YMMV.</blockquote>
<br />
For this experiment I created three images; each one built using one of the three floating-point tunings given above but all containing the same contents and the same versions of all the contents. I then loaded each of the images on my hardware in turn, so I could run the benchmark programs to generate performance data.<br />
<br />
As of the time these images were built (Oct 11, 2019), the HEAD revision of openembedded-core was <span style="font-family: "courier new" , "courier" , monospace;">59938780e7e776d87146002ea939b185f8704408</span> and the head revision of meta-openembedded/meta-oe was <span style="font-family: "courier new" , "courier" , monospace;">fd1a0c9210b162ccb147e933984c755d32899efc</span>.
At that time, the compiler being used was gcc-9.2, and the versions of
various components are: glibc:2.30, bash:5.0, dhrystone:2.1,
linpack:1.0, nbench:2.2.3, sysbench:0.4.12, and whetstone:1.2.<br />
<br />
<h4>
First Impressions</h4>
One of the first interesting things to note is the size of the various binaries:<br />
<br />
<center>
<table border="0" cellspacing="0"><tbody>
<tr><td align="center" height="16"><br /></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">soft</span></b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">softfp</span></b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">hard</span></b></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
</tr>
<tr>
<td align="left" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">whetstone</span></b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">33,172</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">20,236</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">20,444</td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
</tr>
<tr>
<td align="left" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">dhrystone</span></b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">13,752</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">9,660</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">9,660</td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
</tr>
<tr>
<td align="left" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">sysbench</span></b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">81,268</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">77,176</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">77,176</td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
</tr>
<tr>
<td align="left" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">linpack</span></b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">13,744</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">9,652</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">9,652</td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
</tr>
<tr>
<td align="left" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">nbench</span></b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">47,308</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">43,216</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">43,216</td>
<td align="left"><br /></td></tr>
</tbody></table>
</center>
<br />
<ul></ul>
Looking at the disassembly of each of these binaries, it's not hard to see why this is. Disassembling the binaries is as simple as:<br />
<blockquote class="tr_bq">
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">$ <b>arm-oe-linux-gnueabi-objdump -d whetstone</b></span></span></blockquote>
While the <i>softfp</i> and <i>hard</i> programs are filled with VFP instructions (e.g. <span style="font-family: "courier new" , "courier" , monospace;">vldr</span>, <span style="font-family: "courier new" , "courier" , monospace;">vmul.f64</span>, <span style="font-family: "courier new" , "courier" , monospace;">vsub.f64</span>, etc.) the <i>soft</i> program contains calls to various <span style="font-family: "courier new" , "courier" , monospace;">__aeabi_*</span> functions and <span style="font-family: "courier new" , "courier" , monospace;">__adddf3</span>. These functions come from <span style="font-family: "courier new" , "courier" , monospace;">libgcc</span>, a library written by the gcc people to help shore up things that are missing from standard C libraries (such as software emulation of floating-point, see <a href="https://gcc.gnu.org/onlinedocs/gccint/Libgcc.html" target="_blank">here</a> for more info). Interestingly, the code of these functions is linked into the executable itself (and not as a shared library). As you can imagine, emulating floating-point operations in software is going to take a lot of code!<br />
<br />
If you have floating-point hardware, taking advantage of it will shrink the size of your executables (if they use floating-point math).<br />
<br />
<h4>
Whetstone</h4>
<a href="https://en.wikipedia.org/wiki/Whetstone_(benchmark)" target="_blank"><i>whetstone</i></a> is a benchmark program whose primary purpose is to measure floating-point performance. In each image I ran the <i>whetstone</i> program 5 times, timing each run with <i>time</i>, and had it run 1,000,000 loops:<br />
<blockquote class="tr_bq">
# <b>time whetstone 1000000</b></blockquote>
The averages of each test are as follows. Higher MIPS is better, lower time is better:<br />
<br />
<center>
<table border="0" cellspacing="0"><tbody>
<tr><td align="center" colspan="2" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">soft</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">softfp</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">hard</span></b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>MIPS</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>duration [s]</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>MIPS</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>duration [s]</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>MIPS</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>duration [s]</b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">100.16</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">998.4</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1872.84</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">53.4</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1872.84</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">53.4</td></tr>
</tbody></table>
</center>
<br />
<h4>
Dhrystone</h4>
<a href="https://en.wikipedia.org/wiki/Dhrystone" target="_blank">dhrystone</a> is a benchmark used to evaluate integer performance. In each image I ran the whetstone program 5 times, timing each run, and performing 1,000,000 iterations per run:<br />
<blockquote class="tr_bq">
# <b>time echo 1000000 | dhry</b></blockquote>
The averages are as follows. Higher dhry/sec is better, lower time is better:<br />
<br />
<center>
<table border="0" cellspacing="0"><tbody>
<tr><td align="center" colspan="2" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">soft</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">softfp</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">hard</span></b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>dhry/sec</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>duration [ms]</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>dhry/sec</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>duration [ms]</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>dhry/sec</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>duration [ms]</b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">432527.22</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2.3</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">431037.7</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2.3</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">429554.58</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2.3</td></tr>
</tbody></table>
</center>
<br />
<h4>
Sysbench (cpu)</h4>
<a href="https://github.com/akopytov/sysbench" target="_blank">sysbench</a> is a benchmark which includes a bunch of sub-benchmarks, one of which is the "<i>cpu</i>" test. On each image I ran the <i>cpu</i> test 5 times, capping the run-time to 300[s]. The benchmark appears to perform prime factorization, measuring something called "events", and recording run time per event.<br />
<blockquote class="tr_bq">
# <b>time sysbench --max-time=300 --test=cpu run</b></blockquote>
<center>
<table border="0" cellspacing="0"><tbody>
<tr><td align="center" colspan="2" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">soft</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">softfp</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">hard</span></b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>events</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>duration/event [ms]</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>events</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>duration/event [ms]</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>events</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>duration/event [ms]</b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1157.2</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">259.29</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2951.6</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">101.638</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2951</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">101.662</td></tr>
</tbody></table>
</center>
<br />
<br />
As a final test, on each image I ran the <i>cpu</i> test just once without a time limitation, to see how much time it would otherwise take.<br />
<blockquote class="tr_bq">
# <b>time sysbench --test=cpu run</b></blockquote>
<center>
<table border="0" cellspacing="0"><tbody>
<tr><td align="center" colspan="2" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">soft</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">softfp</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">hard</span></b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>events</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>test duration</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>events</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>test duration</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>events</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>test duration</b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">10000</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">43m0.50s</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">10000</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">16m56.499s</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">10000</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">16m56.777</td></tr>
</tbody></table>
</center>
<br />
<h4>
Linpack</h4>
<a href="https://en.wikipedia.org/wiki/LINPACK" target="_blank">linpack</a> is a benchmark testing a computer's ability to perform numerical linear algebra. The program takes one required parameter: the size of the array to use. If you pass "200", it will calculate a 200x200 array. As it runs, it determines how many repetitions to perform, it bases the repetitions on its performance. For each repetition it records how much time it took. When it's done a set of repetitions, it calculates a KFLOPS count, then starts over with a different repetition count.<br />
<br />
For each image I ran the program once with "200" and once with "500". With no hardware floating point support calculating a 200x200 array it starts with 1 repetition, then tries 2, then 4, 8, etc. With hardware floating-point on a 200x200 array it starts with 8 repetitions, then 16, 32, etc. On a 200x200 array the repetition counts common to all images are 8, 16, and 32. On a 500x500 array the repetition counts common to all images are 1 and 2.<br />
<br />
The program never terminates; it keeps increasing the repetition count and going until explicitly killed.<br />
<blockquote class="tr_bq">
# <b>echo 200 | linpack</b> </blockquote>
<center>
<table border="0" cellspacing="0"><tbody>
<tr><td align="center" colspan="3" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">soft</span></b></td>
<td align="center" colspan="3" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">softfp</span></b></td>
<td align="center" colspan="3" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">hard</span></b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>reps</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>time/rep</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>KFLOPS</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>reps</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>time/rep</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>KFLOPS</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>reps</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>time/rep</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>KFLOPS</b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">8</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">4.3</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2718.669</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">8</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">0.64</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">18553.356</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">8</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">0.62</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">19223.389</td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">16</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">8.6</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2718.614</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">16</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1.29</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">18552.917</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">16</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1.25</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">19214.278</td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">32</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">17.2</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2718.792</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">32</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2.58</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">18552.361</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">32</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2.49</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">19212.128</td></tr>
</tbody></table>
</center>
<blockquote class="tr_bq">
# <b>echo 500 | linpack</b></blockquote>
<center>
<table border="0" cellspacing="0"><tbody>
<tr><td align="center" colspan="3" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">soft</span></b></td>
<td align="center" colspan="3" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">softfp</span></b></td>
<td align="center" colspan="3" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">hard</span></b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>reps</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>time/rep</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>KFLOPS</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>reps</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>time/rep</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>KFLOPS</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>reps</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>time/rep</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>KFLOPS</b></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">8.1</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2674.928</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1.38</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">15876.865</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1.38</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">15883.324</td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">16.17</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2674.871</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2.74</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">15878.365</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">2.74</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">15882.516</td></tr>
</tbody></table>
</center>
<br />
<h4>
nbench</h4>
<a href="https://en.wikipedia.org/wiki/NBench" target="_blank">nbench</a> (aka BYTEmark) runs a bunch of sub-tests (including: numerical sort, string sort, bitfield, fp emulation, fourier, assignment, IDEA, huffman, neural net, and LU decomposition) then generates both an <i>integer index</i> and a <i>floating-point index</i>. These indices are relative to what were considered capable machines of the time (mid-1990's).<br />
<br />
This benchmark was run twice on each image, the averaged results are:<br />
<br />
<center>
<table border="0" cellspacing="0"><tbody>
<tr><td align="center" colspan="2" height="16" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">soft</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">softfp</span></b></td>
<td align="center" colspan="2" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b><span style="font-size: small;">hard</span></b></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>integer idx</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>fp idx</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>integer idx</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>fp idx</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>integer idx</b></td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;"><b>fp idx</b></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
<td align="left"><br /></td>
</tr>
<tr>
<td align="center" height="14" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1.054</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">0.1</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1.1095</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">0.961</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">1.109</td>
<td align="center" style="border-bottom: 1px solid #000000; border-color: rgb(0, 0, 0); border-left: 1px solid #000000; border-right: 1px solid #000000; border-style: solid; border-top: 1px solid #000000; border-width: 1px;">0.979</td>
<td align="left"><br /></td></tr>
</tbody></table>
</center>
<br />
<h4>
Conclusions</h4>
Since software floating-point emulation gets added statically to C programs, using hardware floating point makes binaries smaller in programs that perform floating-point calculations. Enabling floating-point in such programs also improves the performance of floating-point operations noticeably. Interestingly, it appears as though integer performance is ever so slightly impacted in the <i>hard</i> case relative to <i>softfp</i>. Therefore it would seem to be that if your entire work-load is floating-point, then go with <i>hard</i>, otherwise if there is both floating-point and considerable integer calculations, <i>softfp</i> might be best.<br />
<br />
As always, test your own application to know which mode is best in your scenario. TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-7175690643695313942019-09-16T17:31:00.001-04:002022-03-21T08:43:15.740-04:00Board Bring-Up: An Introduction to gdb, JTAG, and OpenOCDLately I've been working on getting a recent-ish U-Boot (2018.07) and Linux kernel (5.0.19) running on an SoC that was released back in 2008: the NXP LPC3240 which is based on the ARM926EJ-S processor (NOTE: the ARM926EJ-S was released in 2001).<br />
<br />
Although I had U-Boot working well enough to load and boot Linux, the moment the Linux kernel started printing its boot progress, my console was filled with the sort of garbage that tells an embedded developer they've got the wrong baud rate. Double-checking, and even triple-checking, of the baud rate values, however, showed that every place where it was configured, it had been correctly set to <b>115200 8N1</b>.<br />
<br />
Having a working console is the basis from which the rest of a software developer's board bring-up activities take place! If you can compile a kernel, load it on the board, and get it to print anything, legibly, to the console, then you're already in a really good position. But if there's no working connection via the console, it means more low-level work is needed.<br />
<br />
Going down the hierarchy (from easier to harder), if the console isn't working, then you'll need to see if JTAG is a possibility. If a JTAG isn't available, then you'll need to look for an LED to blink. Blinking an LED to debug one's work during board bring-up isn't uncommon, but it can be a lot more painful. With nothing but (perhaps) a single LED, it can be hard (though strictly not <i>impossible</i>) to communicate something as simple as: "the value at 0x4000 4064 is 0x0008 097e, and I've reached <<i>this</i>> point in the code". Thankfully for me, this particular board has a working JTAG, and there is support for this SoC in OpenOCD.<br />
<br />
JTAG is a very large specification and has a lot of use-cases. For my purposes, JTAG consists of:<br />
<ul>
<li>extra logic that is added to a chip which implements a very specific state machine</li>
<li>a bunch of extra pins (at least 4, but some designs add more) with which to interface to this internal state machine from outside the chip</li>
<li>a set of commands (in the state machine) that can be executed by toggling bits on the external pin interface</li>
</ul>
These commands let you do things such as push individual bits into, or get individual bits out of, a particular device's JTAG scan chain. Depending on how the scan chain is implemented, this could translate to activities such as the ability to read/write registers, and read/write arbitrary values in the memory space (which includes things like peripherals, configuration, etc).<br />
<br />
Most development hosts don't have random GPIO lines available for interfacing, therefore a dongle of some sort is needed to go between the desktop machine and the target board's multi-wire JTAG interface. In days past, these dongles would be connected to the development host via serial or parallel interfaces; nowadays they're mostly USB.<br />
<br />
Armed with a JTAG dongle, in theory it would be possible to start interacting with the target board directly via JTAG commands. However, this could be very tedious as the JTAG commands are very primitive (i.e. having to follow the state machine precisely, and work 1 bit at a time). One of the more common arrangements is to use <i>gdb</i>, which permits the user to perform higher-level actions (i.e. set a breakpoint, read a given 32-bit memory address, list the register contents, etc) and let the software deal with the details. Note, however, <i>gdb</i> itself does not know how to "speak" JTAG nor does it know how to interact with a JTAG dongle. <i>gdb</i> does, however, speak its own command language called the <b><i>remote gdbserver protocol</i></b>. It is OpenOCD which acts as the interpreter between the remote gdbserver protocol on the one hand (e.g. over a network port), and JTAG commands for the target on the other (e.g. over USB to the dongle) marshalling all the data back and forth between the two.<br />
<br />
With the target board powered off, plug the JTAG dongle's pins into the board's JTAG connector; connect the development host to the JTAG dongle via USB.<br />
<br />
Power on the target board.<br />
<br />
Run OpenOCD on the development host. In my specific case the command I invoke is:<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace;">$ openocd -f interface/ftdi/olimex-arm-usb-ocd-h.cfg -f board/phytec_lpc3250.cfg</span></blockquote>
It is important to note that <i>openocd</i> runs as a daemon, and as such, once invoked, does not terminate until explicitly killed. In particular, this command is run in its own terminal, and simply left running until my debugging session is done. All other work that will be done, needs to be performed in other terminals. Perhaps you're thinking: "I'll just run it in the background using an ampersand". That would work, however: as it runs and interacts with <i>gdb</i> and the board, <i>openocd</i> will print out useful information to the terminal. Therefore giving it its own terminal and letting it run independently while keeping it visible is often quite useful. It's always someplace visible on my desktop while debugging.<br />
<br />
OpenOCD needs to know what dongle I'm using (it supports a number of JTAG dongles) and it needs to know the board or SoC to which it is connecting (it has support for many SoCs and boards). Implicit in the choice of dongle is the communication protocol (here USB) and dongle characteristics (properties, product ID, etc). By specifying a target board or SoC, you're letting OpenOCD know things such as how to initialize its connection, the register size, what speed to use, details about how the device needs to be reset, and so on.<br />
<br />
More recently, some development boards come with built-in debug circuitry, including a USB connector, already designed into the target board itself. In these cases the JTAG dongle isn't needed. One simply needs to connect the target board directly to the development host via a single USB cable, and start up OpenOCD (and <i>gdb</i>) giving only one piece of information: the board's name. All other details are implied.<br />
<br />
Running on a GNU/Linux system, <i>gdb</i> works best with ELF executables. <i>gdb</i> can be coerced into working with raw binaries, but when presented with an ELF file, it is provided with a lot more of the data it needs to do its job. But neither the Linux kernel nor U-Boot are ELF binaries. As part of their default build processes, however, both the Linux kernel and U-Boot build systems generate ELF output in addition to the parts that are actually run. A U-Boot build will produce, for example, <span style="font-family: "courier new" , "courier" , monospace;">u-boot.bin</span>, which is the actual U-Boot binary that is stored wherever the bootloader needs to be placed. But in addition to this, a file called <span style="font-family: "courier new" , "courier" , monospace;">u-boot</span> is produced which is its ELF counterpart. Similarly for the Linux kernel, the kernel itself might be found in <span style="font-family: "courier new" , "courier" , monospace;">arch/arm/Image</span>, but its ELF counterpart is <span style="font-family: "courier new" , "courier" , monospace;">vmlinux</span>.<br />
<br />
If you want to debug a Linux kernel via JTAG using <i>gdb</i>, simply invoke:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">$ arm-oe-linux-gnueabi-gdb vmlinux</span> </blockquote>
<br />
Since the target is an ARM board and my host is an x86 board, I need to invoke the cross-gdb program, not the native one (otherwise it won't be able to make sense of the binary instructions). Since I do so much of my work using OpenEmbedded as a basis, when working independently on U-Boot and the kernel, I simply have OpenEmbedded generate an SDK targeting this particular board, and use it for all my work. When invoking this cross-debugger, I simply provide it with the path to, and the name of, the ELF file containing the kernel I have compiled.<br />
<br />
By default <i>openocd</i> listens on port 6666 for tcl connections, port 4444 for telnet connections, and port 3333 for gdb connections. In order to create the link between <i>gdb</i> and <i>openocd</i>, once <i>gdb</i> is up and running you'll need to link them together by issuing the <b><i>target remote</i></b> or <b><i>target extended-remote</i></b> command:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">(gdb) target extended-remote :3333</span></blockquote>
Of course if you've told <i>openocd</i> to listen to a different port, you'll need to make the necessary adjustments to the connection.<br />
<br />
Congratulations! You're now debugging the Linux kernel on your target board via JTAG using <i>gdb</i>! No serial console required!<br />
<br />
In my particular case, although I knew the Linux kernel was doing something, I wasn't sure what exactly was going on since the baud rate via my serial console was messed up. Using this setup I was able to dump the kernel's ring buffer, allowing me to see exactly what the kernel was doing and providing me with valuable debugging information of its boot:<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">(gdb) x /2000bs __log_buf</span></blockquote>
<br />
<br />TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-62520678415773674392019-06-27T22:42:00.001-04:002022-03-21T08:42:16.190-04:00Verizon Struggles to Understand How Email WorksEmail has been around for <a href="https://en.wikipedia.org/wiki/History_of_email" target="_blank">longer than I've been alive</a>! But apparently, 48 years on, it remains too complicated for even a telecommunications company such as Verizon to understand.<br />
<br />
On June 1st I get the following email in my inbox:<br />
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<span style="font-family: Times, "Times New Roman", serif;"><br /></span></div>
<h2 class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<span style="background-color: #cccccc;"><span style="color: blue;"><span style="font-family: Times, "Times New Roman", serif;">Your updated email address needs to be verified.</span></span></span></h2>
<h4 class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<span style="background-color: #cccccc;"><span style="color: blue;"><span style="font-family: Times, "Times New Roman", serif;">To protect your privacy and ensure that we're sending important information to the right place, click below to verify your email address. </span></span></span></h4>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
Turns out someone has just signed up for a Verizon account and given my email address instead of his own. No problem, I'll just <b><i>not</i></b> click on the link and everything should be fine, right?</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
Lol... <i>NOT!</i></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
In the last 3 weeks I've received 11 emails from Verizon... letting me know my new phone is on its way (and verifying my account and address information), confirming my order, providing details of my next bill and plan details, asking me to fill out a survey (let's just say they didn't get top marks in that one!), etc... <i><b>and I never clicked the link!</b></i></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
It's a good thing they sent out that initial "address verification email". Wouldn't want all that personal information going to the wrong person, eh?</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
At the bottom of every email they've sent, there's always an "unsubscribe" link. Great, I'll just click on that... Oh wait, I can't unsubscribe by clicking the link. I have to sign in to my Verizon account before I can unsubscribe. Is that even legal? I thought unsubscribing was supposed to be a one-click thing in the USA?</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
So I figure maybe I'll get a bit creative and ask for a password reset, the system will send me a link, I'll click the link, and be able to change the email address? Nope. Can't do that either. "For security reasons you need to provide the secret PIN that was used when the account was created in order to reset the account". Oh that's nice, at least <i>that</i> part of their system works.</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
Oh, here my solution: on their website, under support, is a messaging app that I can use to contact a customer service rep. I'll use that, chat with a rep, and have them remove my email address from this account. Nope. Can't do that, the app asks that I login to my account before I can chat with a customer service rep from the website.</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
Looking through the emails that I've received so far, I find the name, address, email, and phone of the Verizon customer service rep who signed this person up. Oh this should be the ticket! I'll email her, let her know what's up, then she can use her insider magic to erase my email from this customer's account. Wow! I must have been on something when I thought that was going to fix anything. She outright refused to help. Her reply was "I will reach out to <customer> and ask them to correct the email address". Really?! That's your solution?! The person who didn't know what an email address was in the first place is who we're relying on now to fix this? The person who has no clue what his email address is (or, apparently, what an email address is to begin with) is the genius who's going to get us out of this mess? If he had a clue to begin with, we wouldn't be here, would we?! When I, politely, point this out to her, she then asks if I know <customer>'s email address so she can change it to that. WTF??! How do you expect me to know the correct email address of some random whack-job on the Internet? I'm so stupid, I should have just said "yes" and given her some other random email address (like, maybe her own). Then this would be solved (from my point of view). And if she is capable of changing it (should I have given her some random email address) why can't she just delete mine without asking <genius> to do it? Why would she be able to solve the problem had I provided a reply to her ridiculous question, but can't fix the problem otherwise?</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
So tonight I decided to call Verizon customer support itself and get this sorted out. Spoiler alert: it's still not fixed. First off, the customer-support dial-in system is very adamant that I provide my Verizon phone number and PIN in order to let me do almost anything. In fact, one of the top-level menu items is "if you're not an existing customer" (so this gets me out of having to have a Verizon account) but then if you pick option #6 on the very next menu (for "other") then it asks for your Verizon phone number and PIN!! So I have to call back again and pretend I'm not a current customer but that I want to become one. This finally lets me talk to a person (the "sales" lineup is never busy). I explain the issue. He's very nice and all, but insists that there is no way for him (or anyone else) to change the account information on an account without knowing the PIN of that account.</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
I understand the point. Verizon (like most companies) doesn't trust their own employees (especially the ones at the lower echelons) and therefore has a system in place such that customer service reps can't log themselves into random accounts and mess around with the data. That sounds all fine and good.</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
But in 2019, as <i>sophisticated</i> (or whatever you wish to use) as Verizon's system is, there's no contingency for the scenario whereby a customer puts in the wrong email address other than to wait and hope for the customer to fix the error themselves? Nobody anywhere who was part of designing Verizon's systems ever considered the possibility that random users might (accidentally perhaps?) put in the wrong email address and therefore provide a mechanism to remove such an email address from their system? It just never occurred to them that this might happen?</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
Worse yet, is the fact the original "email verification link" is apparently pointless. Regardless whether the link is clicked or not, if Verizon has an email to send to a customer, the email on file is used whether or not it has been verified.</div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
<br /></div>
<div class="hP" data-legacy-thread-id="16b14ade0a11855d" data-thread-perm-id="thread-f:1635170457224316253" id=":6f0" tabindex="-1">
It seems like a pretty basic oversight. If you're going to have a path whereby the system is going to send out verification emails to verify the email address a random person randomly puts into the system, there should be a little more thought put into what should happen should the email link never get clicked (maybe it could delete itself after a short period?). Or at the very least, a mechanism whereby someone within Verizon can delete an email address from an account (especially if it hasn't been verified). Or even less than that, the "unsubscribe" links at the bottom of the emails should allow a person to unsubscribe without having to log into an account and provide a PIN (especially in the case where the email address has not yet been verified).</div>
TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0tag:blogger.com,1999:blog-3897401118500109418.post-60858916479665101312019-02-02T03:40:00.001-05:002022-03-21T08:38:09.752-04:00LoRa - first stepsIt took all of (maybe?) an hour to setup 2 <a href="https://www.adafruit.com/product/3178" target="_blank">Adafruit Feather M0 with RFM95 LoRa Radio</a> devices and have them ping each other using the simple <a href="https://learn.adafruit.com/adafruit-feather-m0-radio-with-lora-radio-module" target="_blank">getting started guide</a> and default Arduino code. Yes Arduino, boo hiss, I agree. But it was a very simple and easy way to perform a quick test which helps answer a few basic feasibility questions.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-ftB_QZIxcJo/XFUymx0oN6I/AAAAAAAAYaI/x0o4d8vhbQE4YKaMbRhEZknrMnnjylLtwCLcBGAs/s1600/IMG_20190201_232600.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="360" height="320" src="https://2.bp.blogspot.com/-ftB_QZIxcJo/XFUymx0oN6I/AAAAAAAAYaI/x0o4d8vhbQE4YKaMbRhEZknrMnnjylLtwCLcBGAs/s320/IMG_20190201_232600.jpg" width="240" /></a></div>
<br />
<br />
As some of you know, we own a farm, which presents lots of amazing opportunities for electronics projects: remote sensing, remote control, recording, etc. It would be great to know if someone cranks up the heat in the tack room, then leaves without turning it back down again. It would be great to know if someone accidentally leaves a light on, or a door open, somewhere in the barn. It would be great to be alerted if the electric fence goes down. It would be fantastic to be able to track water temperature in numerous places throughout our outdoor wood boiler HVAC system and correlate that with ambient room temperatures and outdoor temperature. It would be even more amazing to be able to track property-wide and area-specific electricity usage and water usage. And perhaps even consider some HVAC control projects too! Then there's motion sensing, detecting cars/people coming and going, gate operations/accessibility, wildlife/herd tracking, mailbox alerts, ..., it's quite a list!<br />
<br />
But before I can even start to dream too much, I need to look at a lot of mundane things and figure out a whole bunch of details. For example: how do I communicate with things over the length (685m) and width (190m) of our property (~30acres)? What's the best way to communicate with things in the barn? Does everything need to be plugged in, or are batteries feasible?<br />
<br />
One of the challenges that might not be readily obvious to most, is that the barn is mostly wrapped in metal. Trying to do wireless things in, around, through, and past an all-metal-wrapped barn is not straight-forward. Even our house has a metal roof. Another challenge is the fact our house is made of field-stone, and has roughly 17" thick concrete/stone walls! Try getting WiFi out of the underground basement through a 17" concrete/stone wall!<br />
<br />
I'm sure to most people, it's obvious WiFi isn't a solution. <i>Maybe</i> sections of the property could be covered by WiFi, but it's certainly not the solution everywhere. And even at that, trying to cover an outdoor area in WiFi requires outdoor antennas, and WiFi extenders (which are not cheap, and can be difficult to get them to work together). Not to mention: WiFi is hard on battery-operated devices. Obviously Bluetooth isn't going to cut it either. So that eliminates all those Espressif ESP8266/ESP32 and BT/BTLE devices. A traditionally popular option would be Zigbee, but I get the feeling its popularity is waning. The rising star today for "IoT things" seems to be LoRa, so I wanted to give that a try. Ideally though, I'd like to try Zigbee too, so I can evaluate it and LoRa side-by-side.<br />
<br />
But how well is LoRa going to work <i>on my property</i>? Sure we hear all sorts of amazing numbers describing the theoretical <a href="https://www.google.ca/search?q=What+is+the+range+of+LoRa" target="_blank">LoRa range</a>, but these results always come with provisos. How well is LoRa going to work from my basement? Through my house's thick walls? Past the all-metal barn? Over the hills? And through the forest?<br />
<br />
Then on top of LoRa itself is this whole LoRaWAN stuff and <a href="https://www.thethingsnetwork.org/docs/lorawan/" target="_blank">The Things Network</a>... (whatever those things are).<br />
<br />
Above the radio we then have to consider microcontrollers. I wouldn't want to wake up one day to find that I had grown overly-biased in my preference for one microcontroller over all others. But having worked with 8-bit PICs, 8-bit AVRs, and 8051s, I have to say: those 32-bit CortexMs from ARM are pretty sweet! Maybe I'll consider using a PIC here or there just to improve my microprocessor breadth, but they won't be a top priority. Another up-and-coming microcontroller that I'll want to experiment with would be one of those smaller RISC-V designs such as the <a href="https://www.sifive.com/chip-designer#fe310" target="_blank">FE310</a>.<br />
<br />
On top of the microcontroller goes the code. As I said above, the Arduino environment is cute for some quick prototyping, but ideally I'd prefer to be closer to the hardware. Popular choices in the maker community include <a href="http://micropython.org/" target="_blank">MicroPython</a> and Adafruit's <a href="https://learn.adafruit.com/welcome-to-circuitpython/what-is-circuitpython" target="_blank">CircuitPython</a>. Those are okay choices and both have their place, but only you're fond of "single control-loop" designs. Through these projects I'm hoping to explore MicroPython, CircuitPython, and, yes, even Arduino stuff, but ultimately I'd like to spend most of my time with things like <a href="https://www.freertos.org/" target="_blank">FreeRTOS</a>, <a href="https://www.zephyrproject.org/" target="_blank">Zephyr</a>, <a href="https://www.mbed.com/en/" target="_blank">mbed</a>, and <a href="http://libopencm3.org/" target="_blank">libopencm3</a>. Any others I should consider?<br />
<br />
Above the "firmware" comes higher-level software such as messaging. I'm guessing <a href="http://mqtt.org/" target="_blank">MQTT</a> is the only sensible choice here?<br />
<br />
I'm still not done. Another item that needs serious attention are all the various hardware choices: hardware form-factors, batteries, weatherproof enclosures, .... If every item is going to be a one-off design, then I can try a bunch of different boards, batteries, enclosures, and form-factors to see which ones work better than others. But if I want to build up an ecosystem of devices all built on the same known platform, then I need to consider standardizing on some of these options.<br />
<br />
I like what <a href="https://www.adafruit.com/" target="_blank">Adafruit</a> has done with their <a href="https://learn.adafruit.com/adafruit-feather" target="_blank">Feather</a> line of <a href="https://www.adafruit.com/category/943" target="_blank">development boards</a>. They're <a href="https://learn.adafruit.com/adafruit-feather/feather-specification" target="_blank">standardized</a>, breadboard-able, have LiPo connectors and charging hardware onboard, and have an ever-growing ecosystem of daughter-boards (<a href="https://www.adafruit.com/category/945" target="_blank">FeatherWings</a>). What's nice about the Feather ecosystem is how the user has a choice of microcontroller for the baseboard itself. I think it would be fair to call Adafruit's Feather ecosystem a form-factor for The Internet of Things. Are there any others worth considering?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-3S65uKAEGJU/XFVK6x5XX7I/AAAAAAAAYaU/STpkq0uR2AMQEcd4Jia0X6riWyjk2TvNgCLcBGAs/s1600/IMG_20190202_000737.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" height="240" src="https://2.bp.blogspot.com/-3S65uKAEGJU/XFVK6x5XX7I/AAAAAAAAYaU/STpkq0uR2AMQEcd4Jia0X6riWyjk2TvNgCLcBGAs/s320/IMG_20190202_000737.jpg" width="320" /></a></div>
<br />
I started out saying how it didn't take very long to get two of these boards sending messages to each other. Although my research had told me that it should work easily, I was still very amazed when I took one of the boards, plugged in a <a href="https://www.buyapi.ca/product/lithium-ion-polymer-battery-3-7v-1000mah/" target="_blank">LiPo battery</a>, put everything inside a <a href="https://www.adafruit.com/product/903" target="_blank">weatherproof enclosure</a>, brought it to the barn, and returned to my desk to find they were still communicating! The barn is about 80m (~260') away, and my office is underground, behind a 17" thick concrete/stone wall! I tweaked the code a little, but didn't make any changes to the radio operation other than to set the frequency. I'm using just a plain, simple 3" wire soldered to the "antenna" pad. Wow!<br />
<br />
And with this little experiment, I've (finally!) started down the path of (hopefully!) many fun, electronics, farm projects! I now know I can at least communicate from my desk to the barn over LoRa using a simple 3" wire antenna and two tiny Feather boards.TrevorWoernerhttp://www.blogger.com/profile/13367691295387497276noreply@blogger.com0