<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
     xmlns:georss="http://www.georss.org/georss"
     xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
     xmlns:media="http://search.yahoo.com/mrss/"><channel>
  <title>zuendmasse.de</title>
  <atom:link href="https://zuendmasse.de/rss.xml" rel="self" type="application/rss+xml" />
  <link>https://zuendmasse.de/</link>
  <description><![CDATA[Adventures of a random geek]]></description>
  <language>en</language>
  <pubDate>Thu, 02 Jun 2022 20:20:32 +0200</pubDate>
  <lastBuildDate>Thu, 02 Jun 2022 20:20:32 +0200</lastBuildDate>
  <generator>Emacs 28.1 Org-mode 9.5.3</generator>
  <webMaster>wose@zuendmasse.de (wose)</webMaster>
  <image>
    <url></url>
    <title>zuendmasse.de</title>
    <link>https://zuendmasse.de/</link>
  </image>


  <item>
    <title>Let's write an embedded-hal-driver</title>
    <link>https://zuendmasse.de/lets-write-an-embedded-hal-driver.html</link>
    <author>wose@zuendmasse.de (wose)</author>
    <guid isPermaLink="false">https://zuendmasse.de/lets-write-an-embedded-hal-driver.html</guid>
    <pubDate>Fri, 23 Feb 2018 00:00:00 +0100</pubDate>

    <description><![CDATA[<p>
    Mid January japaric started <a href="https://github.com/rust-lang-nursery/embedded-wg/issues/39">"The weekly driver initiative"</a> with the goal to
    kick-start releases of platform agnostic <a href="https://docs.rs/embedded-hal/0.1.0/embedded_hal/">embedded-hal</a> based driver crates. In
    this post we'll build an <code>embedded-hal-driver</code> for the <b>AT24C32</b>-EEPROM chip.
    </p>

    <div id="outline-container-org942e1fd" class="outline-3">
    <h3 id="org942e1fd">What&rsquo;s an EEPROM?</h3>
    <div class="outline-text-3" id="text-org942e1fd">
    <p>
    EEPROM stands for electrically erasable read only memory. It is quite
    slow and has a low memory density compared to flash memory, but allows single
    byte operations (read/write). Modern EEPROMs also offer multi byte page reads
    and writes.
    </p>
    </div>
    </div>

    <div id="outline-container-org38d11c7" class="outline-3">
    <h3 id="org38d11c7">What is it good for?</h3>
    <div class="outline-text-3" id="text-org38d11c7">
    <p>
    While you shouldn&rsquo;t use EEPROMs to store huge or often changing data, they are
    useful to hold serial numbers, telephone numbers, configuration data,
    calibration data&#x2026; basically everything which is seldom changed. EEPROM cells
    can typically be rewritten about a million times, so think about it before you
    dump your logs or sensor data into it.
    </p>
    </div>
    </div>

    <div id="outline-container-orgf2d2530" class="outline-3">
    <h3 id="orgf2d2530">AT24C32</h3>
    <div class="outline-text-3" id="text-orgf2d2530">
    <p>
    I happen to own an DS3231 real time clock (RTC) breakout board which also
    contains an Atmel AT24C32 EEPROM and is accessible through <i>i2c</i>-bus. We ignore
    the RTC for now and focus on the EEPROM.
    </p>

    <p>
    A good start is to take a look in the <a href="https://www.elecrow.com/download/24C32.pdf">AT24C32 datasheet</a> to get an overview of
    the chips opcodes and features. The device supports up to eight different <i>i2c</i>
    addresses depending on the state of the <code>A0</code>, <code>A1</code> and <code>A2</code> pin. This means we
    can connect up to eight of these EEPROMs to a single <i>i2c</i>-bus (without address
    modifications at runtime). And there are some <i>commands</i> we&rsquo;ll have to implement
    to actually write or read bytes:
    </p>

    <p>
    single byte write
    page write
    current address read
    random read
    sequential read
    </p>
    </div>
    </div>

    <div id="outline-container-org59bb5ce" class="outline-3">
    <h3 id="org59bb5ce">Electrical connection</h3>
    <div class="outline-text-3" id="text-org59bb5ce">
    <p>
    The device communicates over the <i>i2c</i>-bus to the outside world. Mine is part of
    a RTC breakout board which looks like this:
    </p>


    <div id="org5a7ca40" class="figure">
    <p><img src="../images/ds3231_at24c32.png" alt="ds3231_at24c32.png">
    </p>
    </div>

    <p>
    The orange rectangle marks the AT24C32 chip. The green one shows 3 solder
    bridges you can short to change the <i>i2c</i> address. The red rectangle marks the 4
    pins we need to connect to our test machine. I&rsquo;m using a raspberry pi 2 and the
    following connection:
    </p>

    <table>


    <colgroup>
    <col  class="org-left">

    <col  class="org-left">

    <col  class="org-left">
    </colgroup>
    <thead>
    <tr>
    <th scope="col" class="org-left">RPi pin</th>
    <th scope="col" class="org-left">AT24C32 pin</th>
    <th scope="col" class="org-left">J1 pin</th>
    </tr>
    </thead>
    <tbody>
    <tr>
    <td class="org-left">1 3.3V</td>
    <td class="org-left">8 VCC</td>
    <td class="org-left">5 VCC</td>
    </tr>

    <tr>
    <td class="org-left">9 GND</td>
    <td class="org-left">4 GND</td>
    <td class="org-left">6 GND</td>
    </tr>

    <tr>
    <td class="org-left">3 I2C1_SDA</td>
    <td class="org-left">5 SDA</td>
    <td class="org-left">4 SDA</td>
    </tr>

    <tr>
    <td class="org-left">5 I2C1_SCL</td>
    <td class="org-left">6 SCL</td>
    <td class="org-left">3 SCL</td>
    </tr>
    </tbody>
    </table>
    </div>
    </div>

    <div id="outline-container-org7b0e1ad" class="outline-3">
    <h3 id="org7b0e1ad">Testing the setup</h3>
    <div class="outline-text-3" id="text-org7b0e1ad">
    <p>
    We can now test the connection by scanning the bus for devices. To do this we&rsquo;ll
    first need to enable <i>i2c</i> on the RPi:
    </p>

    <p>
    <code>sudo raspi-config</code>
    <code>5 Interfacing Options</code>
    <code>P5 I2C</code>
    <code>&lt;Yes&gt;</code>
    </p>

    <pre class="example" id="org18b41f6">
    $ ls /dev/i2c*
    /dev/i2c-1
    </pre>

    <p>
    Let&rsquo;s install some helpers:
    </p>

    <pre class="example" id="org4c2db18">
    $ sudo apt-get install -y i2c-tools
    </pre>

    <p>
    And finally check if our device is sitting in the <i>i2c</i>-bus.
    </p>

    <pre class="example" id="org643ba5c">
    $ i2cdetect -y 1
    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
    00:          -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
    60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
    70: -- -- -- -- -- -- -- --
    </pre>

    <p>
    There they are. Address <code>0x68</code> is the RTC and <code>0x57</code> is our AT24C32 because all
    solder bridges are open and the <code>A*</code> pins are pulled up. The <i>base address</i> of
    the device is <code>0b1010000</code> (<code>0x50</code>) and the last 3 LSB are determined by the <code>A*</code>
    pins.
    </p>
    </div>
    </div>

    <div id="outline-container-orgc5e45e5" class="outline-3">
    <h3 id="orgc5e45e5">The driver crate</h3>
    <div class="outline-text-3" id="text-orgc5e45e5">
    <p>
    The hardware works, now let&rsquo;s talk to it. We let cargo create a new crate and
    setup a new target to cross compile to the raspberry pi, so we can quickly build
    an example and test it on our target.
    </p>

    <pre class="example" id="orgd977c64">
    $ cargo new at24cx
    Created library `at24cx` project
    $ cd at24cx
    $ mkdir .cargo
    $ editor .cargo/config &amp;&amp; cat $_
    [target.armv7-unknown-linux-gnueabihf]
    linker = "arm-linux-gnueabihf-gcc-6"
    $ cargo build --target=armv7-unknown-linux-gnueabihf
    Compiling at24cx v0.1.0 (file:///home/wose/projects/rust-embedded/at24cx)
    Finished dev [unoptimized + debuginfo] target(s) in 0.34 secs
    </pre>
    </div>
    </div>

    <div id="outline-container-org7ffc284" class="outline-3">
    <h3 id="org7ffc284">Dependencies</h3>
    <div class="outline-text-3" id="text-org7ffc284">
    <p>
    <code>embedded-hal</code> provides <i>i2c</i> traits we&rsquo;ll use to talk to the <i>i2c</i>-bus in a
    platform agnostic way. To test it we&rsquo;ll need an implementation of the
    <code>embedded-hal</code> traits. <a href="https://github.com/japaric/linux-embedded-hal">linux-embedded-hal</a> provides this implementation for linux
    and thus for the raspberry pi.
    </p>

    <pre class="example" id="org695bb6f">
    $ cargo add embedded-hal
    $ cargo add --dev linux-embedded-hal
    </pre>
    </div>
    </div>

    <div id="outline-container-org5575be0" class="outline-3">
    <h3 id="org5575be0">Write/Read a single byte</h3>
    <div class="outline-text-3" id="text-org5575be0">
    <p>
    Let&rsquo;s try to create a minimal driver to write a single byte to the EEPROM and
    read it back. Another look in the datasheet reveals what we need to send to
    write a single byte:
    </p>


    <div id="org1e7288f" class="figure">
    <p><img src="../images/byte-write.png" alt="byte-write.png">
    </p>
    </div>

    <p>
    the device address (<code>0x57</code>) with the <code>R/W</code> bit <code>0</code> (write to the slave)
    MSBs of the 16 bit address (the memory address is actually just 12 bit for the
    AT24C32)
    LSBs of the 16 bit address
    the data byte
    </p>

    <p>
    What about reading a random memory address?
    </p>


    <div id="orgb57aacc" class="figure">
    <p><img src="../images/random-read.png" alt="random-read.png">
    </p>
    </div>

    <p>
    Similar to writing a single byte, we first need to <i>write</i> the device and memory
    address to the <i>i2c</i>-bus and then start a read by sending the device address
    with the <code>R/W</code> bit <code>1</code> (read from the slave). The EEPROM will then send the data
    at that memory address.
    </p>

    <div class="org-src-container">
    <pre class="src src-rust" id="org23076a7"><span class="org-preprocessor">#![no_std]</span>

    <span class="org-keyword">extern</span> <span class="org-keyword">crate</span> embedded_hal <span class="org-keyword">as</span> hal;

    <span class="org-keyword">use</span> <span class="org-constant">hal</span>::<span class="org-constant">blocking</span>::<span class="org-constant">i2c</span>::{<span class="org-type">Write</span>, <span class="org-type">WriteRead</span>};

    <span class="org-comment-delimiter">// </span><span class="org-comment">we'll add support for the other 7 addresses later</span>
    <span class="org-keyword">pub</span> <span class="org-keyword">const</span> <span class="org-variable-name">ADDRESS</span>: <span class="org-type">u8</span> = 0x57;

    <span class="org-doc">/// AT24Cx Driver</span>
    <span class="org-keyword">pub</span> <span class="org-keyword">struct</span> <span class="org-type">AT24Cx</span>;

    <span class="org-keyword">impl</span> <span class="org-type">AT24Cx</span>
    {
    <span class="org-keyword">pub</span> <span class="org-keyword">fn</span> <span class="org-function-name">new</span>() -&gt; <span class="org-type">Self</span> {
    <span class="org-type">AT24Cx</span> {}
    }

    <span class="org-keyword">pub</span> <span class="org-keyword">fn</span> <span class="org-function-name">write</span>&lt;<span class="org-type">I2C</span>, <span class="org-type">E</span>&gt;(<span class="org-rust-ampersand">&amp;</span><span class="org-keyword">self</span>, <span class="org-variable-name">i2c</span>: <span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> <span class="org-type">I2C</span>, <span class="org-variable-name">address</span>: <span class="org-type">u16</span>, <span class="org-variable-name">byte</span>: <span class="org-type">u8</span>) -&gt; <span class="org-type">Result</span>&lt;(), <span class="org-type">E</span>&gt;
    <span class="org-keyword">where</span>
    <span class="org-variable-name">I2C</span>: <span class="org-type">Write</span>&lt;<span class="org-type">Error</span> = <span class="org-type">E</span>&gt; + <span class="org-type">WriteRead</span>&lt;<span class="org-type">Error</span> = <span class="org-type">E</span>&gt;,
    {
    <span class="org-keyword">let</span> <span class="org-variable-name">msb</span> = (address &gt;&gt; 8) <span class="org-keyword">as</span> <span class="org-type">u8</span>;
    <span class="org-keyword">let</span> <span class="org-variable-name">lsb</span> = (address &amp; 0xFF) <span class="org-keyword">as</span> <span class="org-type">u8</span>;
    i2c.write(<span class="org-type">ADDRESS</span>, <span class="org-rust-ampersand">&amp;</span>[msb, lsb, byte])
    }

    <span class="org-keyword">pub</span> <span class="org-keyword">fn</span> <span class="org-function-name">read</span>&lt;<span class="org-type">I2C</span>, <span class="org-type">E</span>&gt;(<span class="org-rust-ampersand">&amp;</span><span class="org-keyword">self</span>, <span class="org-variable-name">i2c</span>: <span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> <span class="org-type">I2C</span>, <span class="org-variable-name">address</span>: <span class="org-type">u16</span>) -&gt; <span class="org-type">Result</span>&lt;<span class="org-type">u8</span>, <span class="org-type">E</span>&gt;
    <span class="org-keyword">where</span>
    <span class="org-variable-name">I2C</span>: <span class="org-type">Write</span>&lt;<span class="org-type">Error</span> = <span class="org-type">E</span>&gt; + <span class="org-type">WriteRead</span>&lt;<span class="org-type">Error</span> = <span class="org-type">E</span>&gt;,
    {
    <span class="org-keyword">let</span> <span class="org-variable-name">msb</span> = (address &gt;&gt; 8) <span class="org-keyword">as</span> <span class="org-type">u8</span>;
    <span class="org-keyword">let</span> <span class="org-variable-name">lsb</span> = (address &amp; 0xFF) <span class="org-keyword">as</span> <span class="org-type">u8</span>;
    <span class="org-keyword">let</span> <span class="org-keyword">mut</span> <span class="org-variable-name">buffer</span> = [0];
    i2c.write_read(<span class="org-type">ADDRESS</span>, <span class="org-rust-ampersand">&amp;</span>[msb, lsb], <span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> buffer)<span class="org-rust-question-mark">?</span>;
    <span class="org-type">Ok</span>(buffer[0])
    }
    }
    </pre>
    </div>

    <p>
    Now we add an example to actually test our driver.
    </p>
    <div class="org-src-container">
    <pre class="src src-rust" id="orge2215b9"><span class="org-keyword">extern</span> <span class="org-keyword">crate</span> at24cx;
    <span class="org-keyword">extern</span> <span class="org-keyword">crate</span> linux_embedded_hal <span class="org-keyword">as</span> hal;

    <span class="org-keyword">use</span> <span class="org-constant">at24cx</span>::<span class="org-type">AT24Cx</span>;
    <span class="org-keyword">use</span> <span class="org-constant">hal</span>::<span class="org-type">I2cdev</span>;
    <span class="org-keyword">use</span> <span class="org-constant">std</span>::thread;
    <span class="org-keyword">use</span> <span class="org-constant">std</span>::<span class="org-constant">time</span>::<span class="org-type">Duration</span>;

    <span class="org-keyword">fn</span> <span class="org-function-name">main</span>() {
    <span class="org-keyword">let</span> <span class="org-keyword">mut</span> <span class="org-variable-name">dev</span> = <span class="org-type">I2cdev</span>::new(<span class="org-string">"/dev/i2c-1"</span>).unwrap();
    <span class="org-keyword">let</span> <span class="org-variable-name">eeprom</span> = <span class="org-type">AT24Cx</span>::new();

    eeprom.write(<span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> dev, 0x0042, 42).unwrap();

    <span class="org-comment-delimiter">// </span><span class="org-comment">wait 10ms for the write to finish or the eeprom will NAK the next write or read request</span>
    <span class="org-constant">thread</span>::sleep(<span class="org-type">Duration</span>::from_millis(10));

    <span class="org-rust-builtin-formatting-macro">println!</span>(
    <span class="org-string">"The answer to the ultimate question of life, the universe and everything is </span><span class="org-rust-string-interpolation">{}</span><span class="org-string">."</span>,
    eeprom.read(<span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> dev, 0x0042).unwrap()
    );
    }
    </pre>
    </div>

    <p>
    Build and run it on the RPi:
    </p>
    <pre class="example" id="orgcf6560a">
    $ cargo build --target=armv7-unknown-linux-gnueabihf --example rpi
    $ # copy the example to your RPi
    $ ssh pi@pi
    $ ./rpi
    The answer to the ultimate question of life, the universe and everything is 42.
    </pre>

    <p>
    <i>Yay!</i> This driver will now work on any platform which has an <code>embedded-hal</code>
    <i>i2c</i> trait implementation. But there is more. We can get rid of the delay in
    our example by polling the EEPROM for the finished write operation and also
    write and read multiple bytes in one go.
    </p>
    </div>
    </div>

    <div id="outline-container-org05a9aa1" class="outline-3">
    <h3 id="org05a9aa1">Memory pages</h3>
    <div class="outline-text-3" id="text-org05a9aa1">
    <p>
    The memory inside the EEPROM can be visualized as a table. The rows represent
    <i>pages</i> and the columns the data words inside a page. The size of a page and
    data word is device specific. The AT24C32 has a word size of 8 bit (or 1 byte)
    ,a page size of 32 words and has 128 pages (128 * 32 * 8 = 32768 bits).
    </p>

    <p>
    Why is this important? Every time we write or read a word the internal address
    pointer of the EEPROM is incremented, so the next read or write operation will
    use the next byte. But if we hit a page boundary we won&rsquo;t move to the next page
    but instead start at the beginning of the current page (only the lower 5 bits of
    the memory address are incremented). Sending more bytes than the page size (32)
    will overwrite data we already sent.
    </p>


    <div id="org5e64abe" class="figure">
    <p><img src="../images/page-write.png" alt="page-write.png">
    </p>
    </div>

    <p>
    A page write is very similar to single byte write, just send more data bytes
    instead of the <code>STOP</code>.
    </p>

    <div class="org-src-container">
    <pre class="src src-rust">...
    <span class="org-keyword">pub</span> <span class="org-keyword">fn</span> <span class="org-function-name">write_page</span>&lt;<span class="org-type">I2C</span>, <span class="org-type">E</span>&gt;(<span class="org-rust-ampersand">&amp;</span><span class="org-keyword">self</span>, <span class="org-variable-name">i2c</span>: <span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> <span class="org-type">I2C</span>, <span class="org-variable-name">address</span>: <span class="org-type">u16</span>, <span class="org-variable-name">data</span>: <span class="org-rust-ampersand">&amp;</span>[<span class="org-type">u8</span>]) -&gt; <span class="org-type">Result</span>&lt;(), <span class="org-type">E</span>&gt;
    <span class="org-keyword">where</span>
    <span class="org-variable-name">I2C</span>: <span class="org-type">Write</span>&lt;<span class="org-type">Error</span> = <span class="org-type">E</span>&gt; + <span class="org-type">WriteRead</span>&lt;<span class="org-type">Error</span> = <span class="org-type">E</span>&gt;,
    {
    <span class="org-comment-delimiter">// </span><span class="org-comment">limit is the page size or we would overwrite data we jyst sent</span>
    <span class="org-keyword">let</span> <span class="org-variable-name">len</span> = min(data.len(), 32);

    <span class="org-comment-delimiter">// </span><span class="org-comment">2 address bytes + page size</span>
    <span class="org-keyword">let</span> <span class="org-keyword">mut</span>  <span class="org-variable-name">buffer</span> = [0; 34];
    {
    <span class="org-keyword">let</span> (addr, dst) = buffer.split_at_mut(2);
    <span class="org-type">BE</span>::write_u16(addr, address);
    dst[..len].clone_from_slice(<span class="org-rust-ampersand">&amp;</span>data[..len]);
    }

    i2c.write(<span class="org-type">ADDRESS</span>, <span class="org-rust-ampersand">&amp;</span>buffer[..data.len()+2])
    }
    ...
    </pre>
    </div>

    <p>
    Note that we now use the <a href="https://docs.rs/byteorder/1.2.1/byteorder/">byteorder</a> crate to <i>format</i> the address instead of
    doing so by hand. The following example will test this by filling page 1 with
    <code>0xEE</code>.
    </p>

    <div class="org-src-container">
    <pre class="src src-rust"><span class="org-keyword">extern</span> <span class="org-keyword">crate</span> at24cx;
    <span class="org-keyword">extern</span> <span class="org-keyword">crate</span> linux_embedded_hal <span class="org-keyword">as</span> hal;

    <span class="org-keyword">use</span> <span class="org-constant">at24cx</span>::<span class="org-type">AT24Cx</span>;
    <span class="org-keyword">use</span> <span class="org-constant">hal</span>::<span class="org-type">I2cdev</span>;

    <span class="org-keyword">fn</span> <span class="org-function-name">main</span>() {
    <span class="org-keyword">let</span> <span class="org-keyword">mut</span> <span class="org-variable-name">dev</span> = <span class="org-type">I2cdev</span>::new(<span class="org-string">"/dev/i2c-1"</span>).unwrap();
    <span class="org-keyword">let</span> <span class="org-variable-name">eeprom</span> = <span class="org-type">AT24Cx</span>::new();
    eeprom.write_page(<span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> dev, 32, <span class="org-rust-ampersand">&amp;</span>[0xEE; 32]).unwrap();
    }
    </pre>
    </div>

    <p>
    To read more than one byte in one go we&rsquo;ll modify the current <code>read</code> method to
    read an arbitrary amount of bytes. Sequential read operations are not limited to
    a single page. If the end of the memory is reached the internal address pointer
    will roll over and continue at the beginning of the memory. So in theory we
    should be able to read the entire EEPROM with one transaction.
    </p>


    <div id="org778159f" class="figure">
    <p><img src="../images/sequential-read.png" alt="sequential-read.png">
    </p>
    </div>

    <div class="org-src-container">
    <pre class="src src-rust">...
    <span class="org-keyword">pub</span> <span class="org-keyword">fn</span> <span class="org-function-name">read</span>&lt;<span class="org-type">B</span>, <span class="org-type">I2C</span>, <span class="org-type">E</span>&gt;(<span class="org-rust-ampersand">&amp;</span><span class="org-keyword">self</span>, <span class="org-variable-name">i2c</span>: <span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> <span class="org-type">I2C</span>, <span class="org-variable-name">address</span>: <span class="org-type">u16</span>) -&gt; <span class="org-type">Result</span>&lt;<span class="org-type">B</span>, <span class="org-type">E</span>&gt;
    <span class="org-keyword">where</span>
    <span class="org-variable-name">B</span>: <span class="org-type">Unsize</span>&lt;[<span class="org-type">u8</span>]&gt;,
    <span class="org-variable-name">I2C</span>: <span class="org-type">Write</span>&lt;<span class="org-type">Error</span> = <span class="org-type">E</span>&gt; + <span class="org-type">WriteRead</span>&lt;<span class="org-type">Error</span> = <span class="org-type">E</span>&gt;,
    {
    <span class="org-keyword">let</span> <span class="org-keyword">mut</span> <span class="org-variable-name">addr</span> = [0; 2];
    <span class="org-type">BE</span>::write_u16(<span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> addr, address);

    <span class="org-keyword">let</span> <span class="org-keyword">mut</span> <span class="org-variable-name">buffer</span>: <span class="org-type">B</span> = <span class="org-rust-unsafe">unsafe</span> { <span class="org-constant">mem</span>::uninitialized() };
    {
    <span class="org-keyword">let</span> <span class="org-variable-name">slice</span>: <span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> [<span class="org-type">u8</span>] = <span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> buffer;
    i2c.write_read(<span class="org-type">ADDRESS</span>, <span class="org-rust-ampersand">&amp;</span>addr, slice)<span class="org-rust-question-mark">?</span>;
    }

    <span class="org-type">Ok</span>(buffer)
    }
    ...
    </pre>
    </div>

    <p>
    The following example will dump the complete EEPROM memory and we should see our
    <i>answer</i> from the first example somewhere near the beginning of the memory and
    page 1 should contain <code>0xEE</code> for every byte.
    </p>

    <div class="org-src-container">
    <pre class="src src-rust"><span class="org-keyword">extern</span> <span class="org-keyword">crate</span> at24cx;
    <span class="org-keyword">extern</span> <span class="org-keyword">crate</span> linux_embedded_hal <span class="org-keyword">as</span> hal;

    <span class="org-keyword">use</span> <span class="org-constant">at24cx</span>::<span class="org-type">AT24Cx</span>;
    <span class="org-keyword">use</span> <span class="org-constant">hal</span>::<span class="org-type">I2cdev</span>;

    <span class="org-keyword">fn</span> <span class="org-function-name">main</span>() {
    <span class="org-keyword">let</span> <span class="org-keyword">mut</span> <span class="org-variable-name">dev</span> = <span class="org-type">I2cdev</span>::new(<span class="org-string">"/dev/i2c-1"</span>).unwrap();
    <span class="org-keyword">let</span> <span class="org-variable-name">eeprom</span> = <span class="org-type">AT24Cx</span>::new();

    <span class="org-keyword">let</span> <span class="org-variable-name">mem</span>: [<span class="org-type">u8</span>;4096] = eeprom.read(<span class="org-rust-ampersand">&amp;</span><span class="org-keyword">mut</span> dev, 0x0000).unwrap();
    <span class="org-keyword">for</span> <span class="org-variable-name">page</span> <span class="org-keyword">in</span> mem.chunks(32) {
    <span class="org-keyword">for</span> <span class="org-variable-name">byte</span> <span class="org-keyword">in</span> page {
    <span class="org-rust-builtin-formatting-macro">print!</span>(<span class="org-string">"</span><span class="org-rust-string-interpolation">{:X}</span><span class="org-string"> "</span>, byte);
    }
    <span class="org-rust-builtin-formatting-macro">println!</span>();
    }
    }
    </pre>
    </div>

    <p>
    And run it:
    </p>

    <pre class="example" id="org1fae97f">
    $ ./rpi
    41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A FF FF FF FF FF FF
    EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE
    FF FF 2A FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
    FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
    FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
    ...
    </pre>

    <p>
    We can spot the previously set value <code>42</code> (<code>0x2A</code>) at row 3 column 3 with the
    memory address <code>2 * 32 + 2 = 66 (0x0042)</code>, which was the address we used for the
    write. <i>Yay!</i>
    </p>

    <p>
    We can also notice that the start of page 0 is filled with the letters A-Z. This
    may be some remains from factory tests, they weren&rsquo;t written by me.
    </p>
    </div>
    </div>

    <div id="outline-container-orgd7b54e5" class="outline-3">
    <h3 id="orgd7b54e5">Conclusion and TODOs</h3>
    <div class="outline-text-3" id="text-orgd7b54e5">
    <p>
    We now have a platform agnostic driver for the AT24C32 EEPROM. Actually, we can
    also use it with the AT24C64 EEPROM, because they have the same page and word
    size. Many EEPROMs have the same or a very similar interface and they differ
    only in address and page size. Adding other chips should be easy. I&rsquo;ll do some
    refactoring to make this straightforward and add some of the AT24CXXX chips
    myself. Pull requests are always welcome.
    </p>

    <p>
    The current <a href="https://github.com/wose/at24cx">WIP driver is on github</a>. And will be released to <a href="https://crates.io">crates.io</a> after the
    ACK polling has been added. The <a href="https://github.com/wose/at24cx/blob/master/README.md">README.md</a> contains a list of implemented and
    planned features. Feel free to open an issue if something is missing or could be
    improved.
    </p>

    <p>
    I&rsquo;ll try to cover the DS3231 RTC in a later post (<a href="https://github.com/wose/ds3231">WIP driver</a>).
    </p>
    </div>
    </div>
    ]]></description>
</item>
<item>
  <title>GDB + SVD</title>
  <link>https://zuendmasse.de/gdb-svd.html</link>
  <author>wose@zuendmasse.de (wose)</author>
  <guid isPermaLink="false">https://zuendmasse.de/gdb-svd.html</guid>
  <pubDate>Sun, 21 Jan 2018 00:00:00 +0100</pubDate>

  <description><![CDATA[<p>
  If you debug embedded inferiors with GDB you might want to check the state of
  some register of some peripheral. You can do this by hand by just reading the
  memory where the register is mapped. This includes consulting the data sheet to
  get the address which is pretty slow if you need to do this often.
  </p>

  <p>
  There is a GDB plugin called <a href="https://github.com/bnahill/PyCortexMDebug">PyCortexMDebug</a>, which enables you to read or write
  registers, show descriptions and list peripherals of micro controllers. The
  peripheral and register information are loaded from a <a href="http://www.keil.com/pack/doc/CMSIS/SVD/html/index.html">System View Description
  file (SVD)</a> You can find many svd files from different vendors in this
  repository: <a href="https://github.com/posborne/cmsis-svd/">cmsis-svd</a>.
  </p>

  <p>
  Unfortunately the plugin only worked if your inferior is written in C/C++
  because the method of actually reading/writing memory uses c-style type casts.
  This doesn't work if you debug a rust inferior like I did. GDBs python API
  provides methods to directly <a href="https://sourceware.org/gdb/current/onlinedocs/gdb/Inferiors-In-Python.html#index-Inferior_002eread_005fmemory-1">read or write</a> a specific address in the inferiors
  memory. So let's use them: <a href="https://github.com/wose/PyCortexMDebug">https://github.com/wose/PyCortexMDebug</a>
  </p>

  <p>
  A pull request will be made after I tested it a little more.
  </p>

  <p>
  After the plugin installation you can add something like the following to your
  <code>.gdbinit</code> of your project to activate the plugin and load a specific svd file.
  </p>

  <pre class="example" id="orgef995a1">
  source gdb.py
  svd_load STM32F103xx.svd
  </pre>

  <p>
  <code>gdb.py</code> is the one which is part of PyCortexMDebug. You'll have to specify the
  path where you've put it or copy it next to your <code>.gdbinit</code>.
  </p>

  <p>
  After connecting to your target you can use the <code>svd</code> command:
  </p>

  <pre class="example" id="orgb65de63">
  &gt;&gt;&gt; svd
  Available Peripherals:
  FSMC:    Flexible static memory controller
  PWR:     Power control
  RCC:     Reset and clock control
  GPIOA:   General purpose I/O
  GPIOB:   General purpose I/O
  GPIOC:   General purpose I/O
  GPIOD:   General purpose I/O
  GPIOE:   General purpose I/O
  GPIOF:   General purpose I/O
  GPIOG:   General purpose I/O
  AFIO:    Alternate function I/O
  EXTI:    EXTI
  DMA1:    DMA controller
  DMA2:    DMA controller
  SDIO:    Secure digital input/output interface
  RTC:     Real time clock
  BKP:     Backup registers
  IWDG:    Independent watchdog
  WWDG:    Window watchdog
  TIM1:    Advanced timer
  TIM8:    Advanced timer
  TIM2:    General purpose timer
  TIM3:    General purpose timer
  TIM4:    General purpose timer
  TIM5:    General purpose timer
  TIM9:    General purpose timer
  TIM12:   General purpose timer
  TIM10:   General purpose timer
  TIM11:   General purpose timer
  TIM13:   General purpose timer
  TIM14:   General purpose timer
  TIM6:    Basic timer
  TIM7:    Basic timer
  I2C1:    Inter integrated circuit
  I2C2:    Inter integrated circuit
  SPI1:    Serial peripheral interface
  SPI2:    Serial peripheral interface
  SPI3:    Serial peripheral interface
  USART1:  Universal synchronous asynchronous receiver transmitter
  USART2:  Universal synchronous asynchronous receiver transmitter
  USART3:  Universal synchronous asynchronous receiver transmitter
  ADC1:    Analog to digital converter
  ADC2:    Analog to digital converter
  ADC3:    Analog to digital converter
  CAN:     Controller area network
  DAC:     Digital to analog converter
  DBG:     Debug support
  UART4:   Universal asynchronous receiver transmitter
  UART5:   Universal asynchronous receiver transmitter
  CRC:     CRC calculation unit
  FLASH:   FLASH
  &gt;&gt;&gt; svd/x I2C1
  Registers in I2C1:
  CR1:    0x00000001  Control register 1
  CR2:    0x00000018  Control register 2
  OAR1:   0x00000000  Own address register 1
  OAR2:   0x00000000  Own address register 2
  DR:     0x000000B0  Data register
  SR1:    0x00000001  Status register 1
  SR2:    0x00000003  Status register 2
  CCR:    0x00000078  Clock control register
  TRISE:  0x00000019  TRISE register
  &gt;&gt;&gt; svd I2C1 SR1
  Fields in SR1 of peripheral I2C1:
  SMBALERT:  0  SMBus alert
  TIMEOUT:   0  Timeout or Tlow error
  PECERR:    0  PEC Error in reception
  OVR:       0  Overrun/Underrun
  AF:        0  Acknowledge failure
  ARLO:      0  Arbitration lost (master mode)
  BERR:      0  Bus error
  TxE:       0  Data register empty (transmitters)
  RxNE:      0  Data register not empty (receivers)
  STOPF:     0  Stop detection (slave mode)
  ADD10:     0  10-bit header sent (Master mode)
  BTF:       0  Byte transfer finished
  ADDR:      0  Address sent (master mode)/matched (slave mode)
  SB:        1  Start bit (Master mode)
  </pre>
  ]]></description>
</item>
<item>
  <title>PDF multi view</title>
  <link>https://zuendmasse.de/multi-view-pdf.html</link>
  <author>wose@zuendmasse.de (wose)</author>
  <guid isPermaLink="false">https://zuendmasse.de/multi-view-pdf.html</guid>
  <pubDate>Fri, 19 Jan 2018 00:00:00 +0100</pubDate>

  <description><![CDATA[<p>
  While <a href="https://github.com/wose/ts100">playing with Rust on μCs</a> I've always at least one date sheet or reference
  manual open. These pdf files, especially the reference manuals, are huge (&gt; 1k
  pages) and consume a fair amount of RAM when opened in a viewer like <a href="https://wiki.gnome.org/Apps/Evince">evince</a> or
  <a href="https://pwmt.org/projects/zathura/">zathura</a>. I found myself struggling to navigate between different parts of the
  manual with a pretty high frequency. Take a look at some transfer sequence
  diagram, check the description of the control register, go back to the diagram,
  ...
  </p>

  <p>
  What I needed was a way to view at least two different parts of the same pdf
  file at the same time. Turns out no pdf viewer known to me was able to split the
  view into multiple views on the same document. Opening the file two times works,
  but eats the RAM.
  </p>

  <p>
  Someone suggested to implement it as some kind of plugin for Atom. Nahhh never,
  if I had that much RAM to waste I would just open the file several times ;-)
  But wait, Atom is an editor, I use an editor, I use Emacs, I bet Emacs can do
  this.
  </p>

  <p>
  And indeed Emacs would open the pdf file using <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Document-View.html">DocView</a> mode and handle it like a
  normal buffer, which means I can open many windows and just point them at
  different parts of the buffer. Cool but not optimal since I had no way to
  recolor the pdf and don't go blind reading these at night (or day, doesn't
  really matter for me). There is an alternative mode to work with pdf files:
  <a href="https://github.com/politza/pdf-tools">pdf-tools</a>. And it's quite awesome. Using its midnight mode and customizing some
  colors I was back to where I left zathura.
  </p>

  <div class="org-src-container">
  <pre class="src src-emacs-lisp">(custom-set-variables
  '(pdf-view-midnight-colors (<span class="org-keyword">quote</span> (<span class="org-string">"#f2be0f"</span> . <span class="org-string">"#1a1a1a"</span>))))
  </pre>
  </div>


  <div id="org2dc989c" class="figure">
  <p><img src="../images/emacs-pdf-view.png" alt="emacs-pdf-view.png">
  </p>
  </div>

  <p>
  There is even a spacemacs layer you can enable by adding <code>pdf-tools</code> to your
  <code>dotspacemacs-configuration-layers</code>.
  </p>

  <p>
  And there I am wondering why I left Emacs to view pdf files in the first place.
  Stupid me.
  </p>
  ]]></description>
</item>
<item>
  <title>Datenspuren</title>
  <link>https://zuendmasse.de/datenspuren.html</link>
  <author>wose@zuendmasse.de (wose)</author>
  <guid isPermaLink="false">https://zuendmasse.de/datenspuren.html</guid>
  <pubDate>Fri, 03 Nov 2017 00:00:00 +0100</pubDate>

  <description><![CDATA[<p>
  At last years <a href="https://datenspuren.de">Datenspuren</a> I gave a talk about super resolution using neural
  nets titled <i>"Do we have an image enhancer that can bit map?"</i>. The talk was
  <a href="https://media.ccc.de/v/DS2016-7840-do_we_have_an_image_enhancer_that_can_bit_map">recorded</a> and the <a href="https://github.com/wose/ds2016">slides and example net are on github</a>.
  </p>

  <p>
  This year I decided to give a talk I wanted to give for some years now but never
  really got to it. Around 2015 I learned about the ESA Copernicus Program and the
  Sentinel satellites. I was surprised that the data and the tools to process it
  were freely available and open source, but also realized that not many people
  knew about it.
  </p>

  <p>
  I tried to change this (a little bit) with this years talk <i>"Freie Daten(spuren)
  aus dem All"</i>
  </p>

  <p>
  <b>Abstract (de)</b>
  </p>
  <blockquote>
  <p>
  Dieser Vortrag gibt einen kleinen Überblick über das ESA Copernicus Programm,
  einem umfangreichen Erdbeobachtungsprogramm. An Beispielen werden die einzelnen
  Sensoren und Instrumente der Sentinel Satelliten erklärt. Eine abschließende
  Demo zeigt, wie jeder die frei zugänglichen Daten in eindrucksvolle Bilder
  unseres Planeten verwandeln kann.
  </p>
  </blockquote>

  <p>
  <a href="https://github.com/wose/ds2017">Slides</a>
  <a href="https://media.ccc.de/v/DS2017-8680-freie_daten_spuren_aus_dem_all">Video</a>
  </p>
  ]]></description>
</item>
<item>
  <title>Embedded Rust</title>
  <link>https://zuendmasse.de/embedded-rust.html</link>
  <author>wose@zuendmasse.de (wose)</author>
  <guid isPermaLink="false">https://zuendmasse.de/embedded-rust.html</guid>
  <pubDate>Sat, 26 Aug 2017 00:00:00 +0200</pubDate>

  <description><![CDATA[<p>
  I started to play with <a href="https://rust-lang.org">Rust</a> about a year ago. I followed the lecture
  <a href="https://github.com/LukasKalbertodt/programmieren-in-rust"><i>Programmieren in Rust</i> by Lukas Kalbertodt</a> which gives a very good introduction
  of the language concepts. I really enjoyed the lecture and kind of relearned
  programming in the process.
  </p>

  <p>
  In other news, but around the same time, I got a cheap CTC 3D Printer and
  started printing stuff. At first spare and improved parts for the CTC to make it
  more usable and reduce the print failures. Setting up and tweaking the pre
  process toolchain (<a href="http://www.openscad.org/">OpenSCAD</a>, <a href="https://www.freecadweb.org/">FreeCAD</a>, <a href="http://slic3r.org/">Slic3r</a>, ...) to prepare the CAD files was
  part of it. I realized that owning a cheap 3D Printer enables you to build a
  better one. There are plenty of projects and parts on sites like <a href="https://www.thingiverse.com/">Thingiverse</a>
  that you can choose from. So I started to build one.
  </p>


  <div id="org76a5e30" class="figure">
  <p><img src="../images/dragonfly.png" alt="dragonfly.png">
  </p>
  </div>

  <p>
  Most custom build 3D Printers use an Arduino based controller. The firmware
  interprets G-Code from a serial connection or a file on the SD card. Extension
  boards like <a href="http://reprap.org/wiki/RAMPS_1.4">RAMPS</a> come with everything you need to control a hand full of
  stepper motors, a hot end, heat bed, SD card and so on. But just using these
  plug'n'play components would be boring and too easy, right?
  </p>

  <p>
  So why not combine the Rust learning and 3D printer project? Thanks to <a href="https://github.com/japaric">Jorge
  Aparicio</a> and his awesome work and <a href="http://blog.japaric.io/">blog series</a> explaining how to get rust working
  on ARM Cortex-M microcontrollers, it was quite easy to get started.
  </p>

  <p>
  As Rust novice and knowing almost nothing about register level programming I was
  already happy after I got an LED blinking on the <a href="http://www.st.com/en/evaluation-tools/stm32f3discovery.html">STM32F3Discovery</a> and <a href="http://wiki.stm32duino.com/index.php?title=Blue_Pill">Blue Pill</a>
  board. I decided to go with the <i>Blue Pill</i> and its STM32F103 chip for now and
  started connecting all sorts of LCDs, OLEDs and stepper drivers I had laying
  around. After I got comfortable with browsing the huge reference manual and
  using the <a href="https://github.com/japaric/stm32f103xx">generated support crate</a> it was time for a small world real project.
  </p>

  <p>
  Fortunately the soldering iron (TS-100) I bought runs of an stm32f103 and is
  built to be hacked. So I started building an alternative firmware in Rust:
  <a href="http://github.com/wose/ts100">http://github.com/wose/ts100</a>
  </p>


  <div id="orge28b1f7" class="figure">
  <p><img src="../images/ts100.png" alt="ts100.png">
  </p>
  </div>

  <p>
  It doesn't do anything useful yet, but I hope this will change soon as I get
  more time to
  </p>
  ]]></description>
</item>
<item>
  <title>Reset</title>
  <link>https://zuendmasse.de/reset.html</link>
  <author>wose@zuendmasse.de (wose)</author>
  <guid isPermaLink="false">https://zuendmasse.de/reset.html</guid>
  <pubDate>Tue, 22 Aug 2017 00:00:00 +0200</pubDate>

  <description><![CDATA[<p>
  It has been almost two years since the last blog entry and the amount of useful
  information was always questionable so I ditched the whole thing and started
  from scratch. I'm now using <a href="https://github.com/kelvinh/org-page">org-page</a> which boils down to:
  </p>

  <p>
  <code>M-x op/new-post</code>
  write the post as Org file
  <code>git commit -a -m "adds new post"</code>
  <code>M-x op/do-publication</code>
  </p>

  <p>
  to create and publish a new post. We'll see if these are few enough steps for
  the lazy me to keep actually posting some stuff.
  </p>
  ]]></description>
</item>
</channel>
</rss>
