<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on HJZ</title><link>http://hackjumpzero.ca/posts/</link><description>Recent content in Posts on HJZ</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Wed, 26 Nov 2025 00:00:00 +0000</lastBuildDate><atom:link href="http://hackjumpzero.ca/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>TIL - gitsha with dirty</title><link>http://hackjumpzero.ca/posts/2025/11/til-gitsha-with-dirty/</link><pubDate>Wed, 26 Nov 2025 00:00:00 +0000</pubDate><guid>http://hackjumpzero.ca/posts/2025/11/til-gitsha-with-dirty/</guid><description>&lt;p>&lt;code>git describe --always --dirty --match=''&lt;/code>&lt;/p>
&lt;p>This command return the gitsha of HEAD, in short form, and attaches &lt;code>-dirty&lt;/code> suffix if there is change in tracked files. &lt;code>7e68a98&lt;/code>, &lt;code>7e68a98-dirty&lt;/code>.
Staged files is also considered as dirty.&lt;/p>
&lt;p>The &lt;code>--match=&amp;quot;&amp;quot;&lt;/code> avoid matching to any nearby git tags, and always return the gitsha.&lt;/p>
&lt;p>This is helpful sometime in build system for tracking application version.&lt;/p></description><content type="html"><![CDATA[<p><code>git describe --always --dirty --match=''</code></p>
<p>This command return the gitsha of HEAD, in short form, and attaches <code>-dirty</code> suffix if there is change in tracked files. <code>7e68a98</code>, <code>7e68a98-dirty</code>.
Staged files is also considered as dirty.</p>
<p>The <code>--match=&quot;&quot;</code> avoid matching to any nearby git tags, and always return the gitsha.</p>
<p>This is helpful sometime in build system for tracking application version.</p>
]]></content></item><item><title>Cortext M chip reset behaviour</title><link>http://hackjumpzero.ca/posts/2025/04/cortext-m-chip-reset-behaviour/</link><pubDate>Sun, 06 Apr 2025 00:00:00 +0000</pubDate><guid>http://hackjumpzero.ca/posts/2025/04/cortext-m-chip-reset-behaviour/</guid><description>&lt;p>Upon power-on reset, the Cortex-M processor&amp;rsquo;s initial actions involve accessing the vector table
• The core first reads the initial Stack Pointer (SP) from the first entry of the vector table (at address &lt;strong>0x00000000&lt;/strong>)
• Then, the core reads the start Program Counter (PC), which is the reset vector, from the second entry of the vector table (at address &lt;strong>0x00000004&lt;/strong>) The Link Register (LR) is also set to &lt;strong>0xFFFFFFFF&lt;/strong>
• Execution then begins at the address pointed to by the reset vector.&lt;/p></description><content type="html"><![CDATA[<p>Upon power-on reset, the Cortex-M processor&rsquo;s initial actions involve accessing the vector table
• The core first reads the initial Stack Pointer (SP) from the first entry of the vector table (at address <strong>0x00000000</strong>)
• Then, the core reads the start Program Counter (PC), which is the reset vector, from the second entry of the vector table (at address <strong>0x00000004</strong>) The Link Register (LR) is also set to <strong>0xFFFFFFFF</strong>
• Execution then begins at the address pointed to by the reset vector.</p>
<p>While the vector table is initially at <strong>0x00000000</strong>, its location can be changed by writing to the Vector Table Offset Register <strong>(VTOR)</strong>. This allows for relocating the vector table to a different memory location, such as SRAM, for performance optimization or to enable dynamic changes. When setting the offset in the VTOR, the table base must be aligned based on the number of exceptions supported, with a minimum alignment of 32 words (128 bytes) for up to 16 interrupts. For a larger number of interrupts, the alignment must be to the next power of two in terms of the number of words required.</p>
<p><img src="/img/Cortex_M_Reset_vector_table.png" alt="Cortex M Reset vector table"></p>
<p><img src="/img/Cortex_M_Reset_action.png" alt="Cortex M Reset action">
<a href="https://www.keil.com/dd/docs/datashts/arm/cortex_m3/r1p1/ddi0337e_cortex_m3_r1p1_trm.pdf">ddi0337e_cortex_m3_r1p1_trm</a> (Section 5.9 Resets)</p>
<p><img src="/img/Arm_Cortex_M_Vector_Table_Array.png" alt="Arm Cortex M Vector Table Array">
<a href="https://documentation-service.arm.com/static/5f2ac4ab60a93e65927bbdbf">DUI0553.pdf</a> (Section 2.3.4 Vector Table)</p>
<p><img src="/img/Cortex_v7m_Reset_behaviour.png" alt="Cortex v7m Reset behaviour">
<a href="https://www.pjrc.com/teensy/beta/DDI0403D_arm_architecture_v7m_reference_manual.pdf">DDI0403D_arm_architecture_v7m_reference_manual</a> (Section B1.5.5 Reset behaviour)</p>
<p>One special thing with vector table is that, the final compiled vector handler addresses are not power of two. This is because the bit[0] of these reset handlers are used for setting the <code>EPSR.T</code> bit on exception handlings.
<img src="/img/Reset_vector_EPSRT_bit.png" alt="Reset vector EPSRT bit">
<a href="https://www.pjrc.com/teensy/beta/DDI0403D_arm_architecture_v7m_reference_manual.pdf">DDI0403D_arm_architecture_v7m_reference_manual</a> (Section B1.5.3 Vector table)</p>
<p>This kind of bring up the question what is the ESPR register?
<img src="/img/Arm_v7m_xPSR.png" alt="Arm v7m xPSR"></p>
<p>Okay so it is the thumb state, but why does the reset need to enable thumb instructions.
<img src="/img/Cortex_M_thumb.png" alt="Cortex M thumb">
<a href="https://www.pjrc.com/teensy/beta/DDI0403D_arm_architecture_v7m_reference_manual.pdf">DDI0403D_arm_architecture_v7m_reference_manual</a> (Section B1.4.2 The special-purpose program status registers, xPSR)</p>
<p>Okay, this is actually news to me!</p>
]]></content></item><item><title>Goose on weekend side projects</title><link>http://hackjumpzero.ca/posts/2025/03/goose-on-weekend-side-projects/</link><pubDate>Mon, 10 Mar 2025 00:00:00 +0000</pubDate><guid>http://hackjumpzero.ca/posts/2025/03/goose-on-weekend-side-projects/</guid><description>&lt;p>I spent some of my limited spare time between childcare duties working on a project: creating llvm-binary-releases using Goose. The goal was straightforward: take an LLVM release package, extract the specific clang tool binary I needed, and produce a new platform/OS-specific release. I planned to set up a hermit package for clang-format because finding pre-built clang binaries is surprisingly difficult. While native package managers are available, they tend to complicate dependency management in build systems, so I decided to solve the problem myself.&lt;/p></description><content type="html"><![CDATA[<p>I spent some of my limited spare time between childcare duties working on a project: creating llvm-binary-releases using Goose. The goal was straightforward: take an LLVM release package, extract the specific clang tool binary I needed, and produce a new platform/OS-specific release. I planned to set up a hermit package for clang-format because finding pre-built clang binaries is surprisingly difficult. While native package managers are available, they tend to complicate dependency management in build systems, so I decided to solve the problem myself.</p>
<p>Starting with Goose was simple. I asked it to generate a script to download a tarball from a given URL and extract the required binary. It produced about a 100-line bash script that worked well for a task confined to a single source file. However, when I moved on to more complex tasks—such as incorporating bash functions—issues began to appear. Instead of returning proper error codes, Goose used echo to return strings, which caused problems when other parts of the program attempted to use these values. It seemed that Goose had difficulty adhering to the API contracts it had designed. I wondered how other AI tools would handle this situation, but I managed to resolve the problem by asking Goose to rewrite the code in Python. The Python version maintained the API contracts properly.</p>
<p>Next, I requested that Goose create a GitHub workflow to handle the output from the Python script. This task proved challenging. After several rounds of error reports and fixes, Goose made some adjustments, but the changes were sometimes suboptimal, and it often failed to interpret the error messages correctly. In the end, I fixed the issue myself—it turned out to be a one-line problem after I reviewed the documentation.</p>
<p>Overall, the project took about three hours over the weekend, even with interruptions from childcare. Although the final product isn’t perfect, I’m satisfied with the result considering the time and effort involved. In previous experiences, similar projects might have required 3-4 hours of focused work, and I might have abandoned the project when faced with obstacles. For me, using LLMs has proven valuable in jumpstarting and completing these side projects, automating tedious tasks and even producing solid documentation.</p>
<p>Now, I’ll copy this draft into another LLM for a final polish.</p>
<p><em>PS: I copied this draft into the chatgpt for polishing, and did NOT add the &ldquo;another LLM&rdquo; part, just the line of copying this into LLM. And chatgpt recognized Goose as a different LLM and differentiated itself. Anyways just thought it was an interesting detail.</em></p>
]]></content></item><item><title>Dev notes from Feb 2025</title><link>http://hackjumpzero.ca/posts/2025/02/dev-notes-from-feb-2025/</link><pubDate>Fri, 28 Feb 2025 00:00:00 +0000</pubDate><guid>http://hackjumpzero.ca/posts/2025/02/dev-notes-from-feb-2025/</guid><description>&lt;h3 id="git-performance-tracing">Git performance tracing&lt;/h3>
&lt;p>I noticed that some git commands, especially &lt;code>git status&lt;/code>, were taking a long time to execute. Since it&amp;rsquo;s tied to my command prompt, this also slowed down my prompt. By using &lt;code>GIT_TRACE=1&lt;/code>, I could see what git was doing. The issue was that the repository had too many submodules, causing &lt;code>git status&lt;/code> to run on each one, which took time.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ GIT_TRACE&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span> git status
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>14:40:25.548035 git.c:476 trace: built-in: git status
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>14:40:25.550695 run-command.c:667 trace: run_command: cd themes/hello-friend-ng; unset GIT_PREFIX; GIT_DIR&lt;span style="color:#f92672">=&lt;/span>.git git status --porcelain&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>14:40:25.550763 run-command.c:759 trace: start_command: /opt/homebrew/opt/git/libexec/git-core/git status --porcelain&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>14:40:25.557470 git.c:476 trace: built-in: git status --porcelain&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>On branch main
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Your branch is up to date with &lt;span style="color:#e6db74">&amp;#39;origin/main&amp;#39;&lt;/span>.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>14:40:25.567125 run-command.c:667 trace: run_command: GIT_INDEX_FILE&lt;span style="color:#f92672">=&lt;/span>.git/index git submodule summary --cached --for-status --summary-limit -1 HEAD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>14:40:25.567200 run-command.c:759 trace: start_command: /opt/homebrew/opt/git/libexec/git-core/git submodule summary --cached --for-status --summary-limit -1 HEAD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>14:40:25.573148 git.c:769 trace: exec: git-submodule summary --cached --for-status --summary-limit -1 HEAD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="fish-shell-performance-tracing">Fish shell performance tracing&lt;/h3>
&lt;p>Similarly, the fish shell has a profiling feature:&lt;/p></description><content type="html"><![CDATA[<h3 id="git-performance-tracing">Git performance tracing</h3>
<p>I noticed that some git commands, especially <code>git status</code>, were taking a long time to execute. Since it&rsquo;s tied to my command prompt, this also slowed down my prompt. By using <code>GIT_TRACE=1</code>, I could see what git was doing. The issue was that the repository had too many submodules, causing <code>git status</code> to run on each one, which took time.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ GIT_TRACE<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span> git status
</span></span><span style="display:flex;"><span>14:40:25.548035 git.c:476               trace: built-in: git status
</span></span><span style="display:flex;"><span>14:40:25.550695 run-command.c:667       trace: run_command: cd themes/hello-friend-ng; unset GIT_PREFIX; GIT_DIR<span style="color:#f92672">=</span>.git git status --porcelain<span style="color:#f92672">=</span><span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>14:40:25.550763 run-command.c:759       trace: start_command: /opt/homebrew/opt/git/libexec/git-core/git status --porcelain<span style="color:#f92672">=</span><span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>14:40:25.557470 git.c:476               trace: built-in: git status --porcelain<span style="color:#f92672">=</span><span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>On branch main
</span></span><span style="display:flex;"><span>Your branch is up to date with <span style="color:#e6db74">&#39;origin/main&#39;</span>.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>14:40:25.567125 run-command.c:667       trace: run_command: GIT_INDEX_FILE<span style="color:#f92672">=</span>.git/index git submodule summary --cached --for-status --summary-limit -1 HEAD
</span></span><span style="display:flex;"><span>14:40:25.567200 run-command.c:759       trace: start_command: /opt/homebrew/opt/git/libexec/git-core/git submodule summary --cached --for-status --summary-limit -1 HEAD
</span></span><span style="display:flex;"><span>14:40:25.573148 git.c:769               trace: exec: git-submodule summary --cached --for-status --summary-limit -1 HEAD
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><h3 id="fish-shell-performance-tracing">Fish shell performance tracing</h3>
<p>Similarly, the fish shell has a profiling feature:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>       -p or --profile<span style="color:#f92672">=</span>PROFILE_FILE
</span></span><span style="display:flex;"><span>              when fish exits, output timing information on all executed commands to the specified file.  This excludes time spent starting up and reading the configuration.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       --profile-startup<span style="color:#f92672">=</span>PROFILE_FILE
</span></span><span style="display:flex;"><span>              Will write timing <span style="color:#66d9ef">for</span> fish startup to specified file.
</span></span></code></pre></div><p>The profile file looks like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Time    Sum     Command
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">115</span>     <span style="color:#ae81ff">10404135</span>        &gt; __fish_print_help fish
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">435</span>     <span style="color:#ae81ff">437</span>     -&gt; source /opt/homebrew/Cellar/fish/4.0.0/share/fish/functions/__fish_print_help.fish
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span>       <span style="color:#ae81ff">2</span>       --&gt; <span style="color:#66d9ef">function</span> __fish_print_help --description <span style="color:#e6db74">&#34;Print help message for the specified fish function or builtin&#34;</span> --argument-names item error_message...
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span>       <span style="color:#ae81ff">2</span>       -&gt; switch $item...
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>       <span style="color:#ae81ff">21</span>      -&gt; <span style="color:#66d9ef">if</span> not test -e <span style="color:#e6db74">&#34;</span>$__fish_data_dir<span style="color:#e6db74">/man/man1/</span>$item<span style="color:#e6db74">.1&#34;</span> -o -e <span style="color:#e6db74">&#34;</span>$__fish_data_dir<span style="color:#e6db74">/man/man1/</span>$item<span style="color:#e6db74">.1.gz&#34;</span>...
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">20</span>      <span style="color:#ae81ff">20</span>      --&gt; not test -e <span style="color:#e6db74">&#34;</span>$__fish_data_dir<span style="color:#e6db74">/man/man1/</span>$item<span style="color:#e6db74">.1&#34;</span> -o -e <span style="color:#e6db74">&#34;</span>$__fish_data_dir<span style="color:#e6db74">/man/man1/</span>$item<span style="color:#e6db74">.1.gz&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span>       <span style="color:#ae81ff">2</span>       -&gt; set -l help
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>       <span style="color:#ae81ff">1</span>       -&gt; set -l format
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>       <span style="color:#ae81ff">0</span>       -&gt; set -l cols
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>       <span style="color:#ae81ff">72</span>      -&gt; <span style="color:#66d9ef">if</span> test -n <span style="color:#e6db74">&#34;</span>$COLUMNS<span style="color:#e6db74">&#34;</span>...
</span></span></code></pre></div>]]></content></item><item><title>Trigger DFU via USB on nRF52840 Dongle</title><link>http://hackjumpzero.ca/posts/2024/04/trigger-dfu-via-usb-on-nrf52840-dongle/</link><pubDate>Sat, 06 Apr 2024 00:00:00 +0000</pubDate><guid>http://hackjumpzero.ca/posts/2024/04/trigger-dfu-via-usb-on-nrf52840-dongle/</guid><description>&lt;p>The &lt;a href="https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle">NRF5280 dongle&lt;/a> is a great embedded development platform, especially for hobbyist project or quick prototyping. There is also a very similar product from &lt;a href="https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/programming/">Make Diary&lt;/a> with slightly different PCBA layout. It is generally a decent utility tool for BLE related work. These functionality can all be done out of box with the nrf desktop tool without doing any programming.&lt;/p>
&lt;p>There are plenty of blog post on this already that covers introductory programming with the nordic part.
But one interesting feature that I run into while working with this dongle was how to trigger DFU programming quickly.&lt;/p></description><content type="html"><![CDATA[<p>The <a href="https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle">NRF5280 dongle</a> is a great embedded development platform, especially for hobbyist project or quick prototyping. There is also a very similar product from <a href="https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/programming/">Make Diary</a> with slightly different PCBA layout. It is generally a decent utility tool for BLE related work. These functionality can all be done out of box with the nrf desktop tool without doing any programming.</p>
<p>There are plenty of blog post on this already that covers introductory programming with the nordic part.
But one interesting feature that I run into while working with this dongle was how to trigger DFU programming quickly.</p>
<p>The nRF52840 dongle support DFU programming via it&rsquo;s bootloader, where one can use <code>nrfutil</code> program the hardware.
The dongle can be reboot into DFU mode via the side reset button.
<img src="/img/NRF52840_dongle_pcb_black_white.png" alt="NRF52840 dongle pcb black white">
The dongle&rsquo;s red LED goes into this slow glow effect, and the usb device is re-enumerated as
<code>ID 1915:521f Nordic Semiconductor ASA Open DFU Bootloader</code>
All this mean the dongle is ready for DFU programming now!</p>
<p>Now you can a command like to issue the programming:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ nrfutil device program --firmware dfu_package.zip --traits nordicDfu 
</span></span></code></pre></div><p>In addition you can create the <code>dfu_package.zip</code> file with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ nrfutil nrf5sdk-tools pkg generate --hw-version <span style="color:#ae81ff">52</span> --sd-req<span style="color:#f92672">=</span>0x00 --application application.zip --application-version <span style="color:#ae81ff">1</span> dfu_package.zip
</span></span></code></pre></div><p>This flow works great for 90% of development flows. You will need to be careful not to accidentally erase the UICR region, or else the bootloader will no longer boot into DFU. I learned this the hardware. If you do end up get the hardware into a state where bootloader don&rsquo;t enter DFU mode, you will need to get a jtag programmer and connect the jtag pins to the dongle to programming the old fashion way.</p>
<p>But these are not what I want to focus on here, I want to focus on how to trigger the DFU mode to begin with.</p>
<p>I am a lazy person, the idea of having to manually press a button on the hardware to start FW programming is just very tiresome to me. Not to mention doing this tens or hundreds times a day.</p>
<h1 id="triggering-dfu-mode-via-usb">Triggering DFU mode via USB</h1>
<p>Essentially on the nRF52840 dongle, just setting the reset pins cause the MCU to reboot into bootloader and bootloader code detect that reset pin are set and enter into DFU mode.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#a6e22e">nrf_gpio_cfg_output</span>(BSP_SELF_PINRESET_PIN);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">nrf_gpio_pin_clear</span>(BSP_SELF_PINRESET_PIN);
</span></span></code></pre></div><p>The hard part is somehow getting a signal from the host machine to the target device to reset the pin.</p>
<p>But luckily this is all reasonably <a href="https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/lib_dfu_trigger_usb.html">documented</a>!
In addition there is a official <a href="https://www.usb.org/sites/default/files/DFU_1.1.pdf">standard</a> for this, Nordic implementation isn&rsquo;t fully compliant but it&rsquo;s close enough.
The nrfsdk provide this helpful <a href="https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/group__nrf__dfu__trigger__usb.html">component</a> anyone can simply include in their FW, some configuration with <code>sdk_config.h</code> is required, as with everything in nrfsdk.</p>
<p>If setup correct it should show up as new vendor interface similar to.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>DEVICE ID 05ac:0256 on Bus <span style="color:#ae81ff">000</span> Address 007 <span style="color:#f92672">=================</span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>  CONFIGURATION 1: <span style="color:#ae81ff">100</span> mA <span style="color:#f92672">==================================</span>
</span></span><span style="display:flex;"><span>  ...
</span></span><span style="display:flex;"><span>    INTERFACE 0: Vendor Specific <span style="color:#f92672">===========================</span>
</span></span><span style="display:flex;"><span>     bLength            :    0x9 <span style="color:#f92672">(</span><span style="color:#ae81ff">9</span> bytes<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>     bDescriptorType    :    0x4 Interface
</span></span><span style="display:flex;"><span>     bInterfaceNumber   :    0x0
</span></span><span style="display:flex;"><span>     bAlternateSetting  :    0x0
</span></span><span style="display:flex;"><span>     bNumEndpoints      :    0x0
</span></span><span style="display:flex;"><span>     bInterfaceClass    :   0xff Vendor Specific
</span></span><span style="display:flex;"><span>     bInterfaceSubClass :    0x1
</span></span><span style="display:flex;"><span>     bInterfaceProtocol :    0x1
</span></span><span style="display:flex;"><span>     iInterface         :    0x0
</span></span></code></pre></div><p>Therefore by setting up a control transfer to the usb device like below, it should in theory trigger the dongle to reboot in DFU mode.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>libusb1_backend <span style="color:#f92672">=</span> usb<span style="color:#f92672">.</span>backend<span style="color:#f92672">.</span>libusb1<span style="color:#f92672">.</span>get_backend(
</span></span><span style="display:flex;"><span>    find_library<span style="color:#f92672">=</span><span style="color:#66d9ef">lambda</span> x: <span style="color:#e6db74">&#34;/opt/homebrew/lib/libusb-1.0.0.dylib&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>dev <span style="color:#f92672">=</span> usb<span style="color:#f92672">.</span>core<span style="color:#f92672">.</span>find(idVendor<span style="color:#f92672">=</span><span style="color:#ae81ff">0x1915</span>, idProduct<span style="color:#f92672">=</span><span style="color:#ae81ff">0x521f</span>, backend<span style="color:#f92672">=</span>libusb1_backend)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>bmRequestType <span style="color:#f92672">=</span> usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>build_request_type(
</span></span><span style="display:flex;"><span>    usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>CTRL_OUT, usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>CTRL_TYPE_CLASS, usb<span style="color:#f92672">.</span>util<span style="color:#f92672">.</span>CTRL_RECIPIENT_DEVICE
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">try</span>:
</span></span><span style="display:flex;"><span>    dev<span style="color:#f92672">.</span>ctrl_transfer(bmRequestType, <span style="color:#ae81ff">0x00</span>, timeout<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">except</span> usb<span style="color:#f92672">.</span>core<span style="color:#f92672">.</span>USBError:
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">pass</span>
</span></span></code></pre></div><p>If you noticed the dongle rebooting but not entering DFU, it&rsquo;s likely resetting or crashing somewhere before the reset pin is set. Just check the code path to <code>dfu_trigger_evt_handler()</code> in <code>components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.c</code> function free of other issue. For example I had used the log backend, but didn&rsquo;t set it up correctly and it was causing the dongle to crash on <code>NRF_LOG_FINAL_FLUSH()</code> right before the reset pin is set.</p>
]]></content></item></channel></rss>