<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://www.bigdick.live/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https:&#x2F;&#x2F;www.bigdick.live</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>这是Web Feed，又称为Atom Feed，把现在的网址复制到新闻阅读器即可订阅本站文章。造访「About Feeds」来了解更多资讯。</tabi:about_feeds>
        <tabi:visit_the_site>造访网站</tabi:visit_the_site>
        <tabi:recent_posts>近期文章</tabi:recent_posts>
        <tabi:last_updated_on>更新于 $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>Rust</tabi:current_section>
    </tabi:metadata><link rel="extra-stylesheet" href="https://www.bigdick.live/skins/black-orange.css?h=c64b7f81e34a143cd725" /><title>孙瑜 - Rust</title>
        <subtitle>孙瑜的个人首页：生物信息、数据科学、软件工程，以及公开简历、项目和文章。</subtitle>
    <link href="https://www.bigdick.live/tags/rust/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://www.bigdick.live/tags/rust/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2024-01-29T00:00:00+00:00</updated><id>https://www.bigdick.live/tags/rust/atom.xml</id><entry xml:lang="zh-Hans">
        <title>Rust单片机编程：用一块STM32板发送http请求</title>
        <published>2024-01-29T00:00:00+00:00</published>
        <updated>2024-01-29T00:00:00+00:00</updated>
        <author>
            <name>孙瑜</name>
        </author>
        <link rel="alternate" href="https://www.bigdick.live/blog/stm32f407-http/" type="text/html"/>
        <id>https://www.bigdick.live/blog/stm32f407-http/</id>
        
            <content type="html">&lt;blockquote&gt;
&lt;p&gt;本文多处参考了&lt;a class=&quot;external&quot; rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rust-embedded.org&#x2F;book&#x2F;&quot;&gt;The Embedded Rust Book&lt;&#x2F;a&gt;，建议对Rust嵌入式开发尚不熟悉的同学反复观看这本书。&lt;br &#x2F;&gt;
由于例子使用的开发板为&lt;a class=&quot;external&quot; rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rust-embedded.org&#x2F;book&#x2F;intro&#x2F;hardware.html#stm32f3discovery-the-f3&quot;&gt;STM32F3DISCOVERY&lt;&#x2F;a&gt;，与&lt;a href=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;#shi-yan-cai-liao&quot;&gt;我们的&lt;&#x2F;a&gt;有一定区别，因此各种操作与书中提及多有出入，&lt;strong&gt;以本文为准&lt;&#x2F;strong&gt;。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;shi-yan-cai-liao&quot;&gt;实验材料&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;一块STM32F407板，板载WIFI模块（ESP8266）&lt;&#x2F;li&gt;
&lt;li&gt;服务器：Ubuntu 22.04.1，非常多的USB 3.0&#x2F;3.1接口，无图形界面&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;huan-jing-pei-zhi&quot;&gt;环境配置&lt;&#x2F;h2&gt;
&lt;p&gt;在一切开始之前，首先使用合适的Type-C线将服务器的任一USB口与板子的CMSIS-DAP接口连接。&lt;&#x2F;p&gt;
&lt;p&gt;基本的编译、烧写和调试（仿真等）环境可以参照&lt;a class=&quot;external&quot; rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rust-embedded.org&#x2F;book&#x2F;intro&#x2F;install&#x2F;linux.html&quot;&gt;这一章节&lt;&#x2F;a&gt;配置，此处仅列举需要修改的步骤和有必要补充的信息：&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zi-ding-yi-udevgui-ze&quot;&gt;自定义&lt;code&gt;udev&lt;&#x2F;code&gt;规则&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：这一小节与&lt;em&gt;The Embedded Rust Book&lt;&#x2F;em&gt;出入非常大&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;我们希望OpenOCD等在不需要root权限的情况下就可以自由与开发板通讯，因此需要自定义&lt;code&gt;udev&lt;&#x2F;code&gt;的规则。运行&lt;code&gt;lsusb&lt;&#x2F;code&gt;命令列出USB设备信息，我们可能获得类似如下的内容：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bus 002 Device 002: ID 174c:3074 ASMedia Technology Inc. ASM1074 SuperSpeed hub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bus 001 Device 007: ID c251:f001 Keil Software, Inc. CMSIS-DAP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bus 001 Device 002: ID 174c:2074 ASMedia Technology Inc. ASM1074 High-Speed hub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这里注意&lt;strong&gt;行末&lt;&#x2F;strong&gt;设备名为&lt;code&gt;CMSIS-DAP&lt;&#x2F;code&gt;的设备即为我们的板子&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。我们以这行为例，解读一下&lt;code&gt;lsusb&lt;&#x2F;code&gt;返回内容的含义：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bus 001&lt;&#x2F;strong&gt;：表示设备连接到&lt;code&gt;001&lt;&#x2F;code&gt;号总线&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Device 007&lt;&#x2F;strong&gt;：表示这是连接到该总线上的第&lt;code&gt;007&lt;&#x2F;code&gt;号设备&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ID c251:f001&lt;&#x2F;strong&gt;: 这里的ID分为两部分：第一部分是&lt;code&gt;idVendor&lt;&#x2F;code&gt;（设备产商），值为&lt;code&gt;c251&lt;&#x2F;code&gt;;第二部分为&lt;code&gt;idProduct&lt;&#x2F;code&gt;（设备类型编号），值为&lt;code&gt;f001&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;有了&lt;code&gt;idVendor&lt;&#x2F;code&gt;和&lt;code&gt;idProduct&lt;&#x2F;code&gt;，接下来我们需要在&lt;code&gt;&#x2F;etc&#x2F;udev&#x2F;rules.d&#x2F;70-st-link.rules&lt;&#x2F;code&gt;文件里追加一行（若无文件则新建）&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# OWNER的值请填写开发者自己使用的用户名&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ATTRS{idVendor}==&amp;quot;c251&amp;quot;, ATTRS{idProduct}==&amp;quot;f001&amp;quot;, OWNER=&amp;quot;ysun&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;写好规则后使用下述命令应用（&lt;strong&gt;无需拔掉设备重新插上&lt;&#x2F;strong&gt;）：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 这里的action参数至关重要&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 如果不指定它的值为change，内核会通知udev将所有设备都认作新设备&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 这可能有非常恶劣的影响&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; udevadm control --reload-rules&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; udevadm trigger --action=change&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;bian-yi-an-zhuang-openocd&quot;&gt;编译安装OpenOCD&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;The Embedded Rust Book&lt;&#x2F;em&gt;中的指引为&lt;a class=&quot;external&quot; rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rust-embedded.org&#x2F;book&#x2F;intro&#x2F;install&#x2F;linux.html#packages&quot;&gt;使用包管理器直接安装OpenOCD&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;但对于某些情况，比如我们的Ubuntu 22.04.1，通过&lt;code&gt;apt&lt;&#x2F;code&gt;安装的OpenOCD为v0.11.0版本。&lt;&#x2F;p&gt;
&lt;p&gt;这一版对STM32F4x系列的支持还比较糟糕，因此&lt;strong&gt;墙裂建议&lt;&#x2F;strong&gt;手动编译一下最新的OpenOCD以防止犯病：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 安装（编译时）必需依赖&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; apt install libtool libhidapi-dev libusb-1.0-0-dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;git&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clone https:&#x2F;&#x2F;github.com&#x2F;openocd-org&#x2F;openocd.git&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt; cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; openocd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;configure&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --enable-cmsis-dap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; make install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;huan-jing-yan-zheng&quot;&gt;环境验证&lt;&#x2F;h3&gt;
&lt;p&gt;为检验工具和驱动是否已被正确配置，我们需要验证OpenOCD能否正常工作（与板上自带的ST-Link调试硬件通信）。在项目根目录下创建&lt;code&gt;openocd.cfg&lt;&#x2F;code&gt;文件，并写入:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 设备接口配置文件&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;source [find interface&#x2F;cmsis-dap.cfg]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 理论上udev规则配置好可以自动获取到，若不能则可以手动指定：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# cmsis_dap_vid_pid 0xc251 0xf001&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 这是一个历史遗留问题，其实是CMSIS-DAP v2 bulk interface自动检测的bug&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 对于一些v1的设备会误被判做是v2，导致通信失败，详见这个commit：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# https:&#x2F;&#x2F;github.com&#x2F;openocd-org&#x2F;openocd&#x2F;commit&#x2F;3da0c2504c14ea0736b973fa0b5085c42a9c6ce8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 该bug在v0.12.0被修复，对之前的版本可以加上下面这行&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# cmsis_dap_backend hid&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 目标芯片配置文件&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;source [find target&#x2F;stm32f4x.cfg]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;此时，运行&lt;code&gt;openocd&lt;&#x2F;code&gt;，应该会有类似输出：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Open On-Chip Debugger 0.11.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Licensed under GNU GPL v2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;For bug reports, read&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        http:&#x2F;&#x2F;openocd.org&#x2F;doc&#x2F;doxygen&#x2F;bugs.html&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : auto-selecting first available session transport &amp;quot;swd&amp;quot;. To override use &amp;#39;transport select &amp;lt;transport&amp;gt;&amp;#39;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : Listening on port 6666 for tcl connections&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : Listening on port 4444 for telnet connections&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : CMSIS-DAP: SWD  Supported&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : CMSIS-DAP: FW Version = ħŮ�Ƽ�&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : CMSIS-DAP: Interface Initialised (SWD)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : SWCLK&#x2F;TCK = 1 SWDIO&#x2F;TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : CMSIS-DAP: Interface ready&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : clock speed 2000 kHz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : SWD DPIDR 0x2ba01477&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : starting gdb server for stm32f4x.cpu on 3333&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Info : Listening on port 3333 for gdb connections&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;并且程序阻塞住了控制台。&lt;&#x2F;p&gt;
&lt;p&gt;至此环境配置完毕。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fang-zhen&quot;&gt;仿真&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;在开始仿真调试前，建议先用&lt;code&gt;cargo-generate&lt;&#x2F;code&gt;&lt;a class=&quot;external&quot; rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rust-embedded.org&#x2F;book&#x2F;start&#x2F;qemu.html#using-cargo-generate&quot;&gt;从模板仓库开始初始化一个实验项目&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;仿真大致操作与&lt;em&gt;The Embedded Rust Book&lt;&#x2F;em&gt;无异，但由于我们的板子是STM32F4x，故QEMU的参数要做一定调整。&lt;&#x2F;p&gt;
&lt;p&gt;比如，&lt;code&gt;.cargo&#x2F;config.toml&lt;&#x2F;code&gt;中需要增加这些内容：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;target.thumbv7em-none-eabihf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;runner&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;qemu-system-arm -cpu cortex-m4 -machine netduinoplus2 -nographic -semihosting-config enable=on,target=native -kernel&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;target&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;thumbv7em-none-eabihf&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;然后就可以正常仿真了（会隐式地以上述参数调用QEMU）：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cargo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run --example hello --release&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果需要用GDB调试，只需要将启动QEMU的参数如上述&lt;code&gt;.cargo&#x2F;config.toml&lt;&#x2F;code&gt;文件中替换即可。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shang-ying-jian&quot;&gt;上硬件&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;nei-cun-bu-ju&quot;&gt;内存布局&lt;&#x2F;h3&gt;
&lt;p&gt;这部分最重要的就是搞清楚板子的内存布局，要确定Flash和SRAM的起始点和长度以确保编译和运行时的行为正确。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;主要参照 ST 的 RM0090 文档（Rev 19）。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h4 id=&quot;tai-chang-bu-kan&quot;&gt;太长不看&lt;&#x2F;h4&gt;
&lt;p&gt;在项目根目录的memory.x文件中，写入：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MEMORY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;* NOTE 1 K = 1 KiBi = 1024 bytes *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;* TODO Adjust these memory regions to match your device memory layout *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;* These values correspond to the LM3S6965, one of the few devices QEMU can emulate *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  FLASH : ORIGIN = 0x08000000, LENGTH = 512K&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  RAM : ORIGIN = 0x20000000, LENGTH = 128K&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;详细依据见下文。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;flashbu-ju&quot;&gt;Flash布局&lt;&#x2F;h4&gt;
&lt;p&gt;架构图在第&lt;strong&gt;73&lt;&#x2F;strong&gt;页：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;img&#x2F;flash_arch.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;我们可以看到，从interface到memory是一条总线连接的，即主内存在使用上是不分区的，即Flash的长度应为&lt;strong&gt;所有Sector的大小之和&lt;&#x2F;strong&gt;。为了提升性能，对指令码和数据码各自有对应的cache，但不影响主内存的分布。&lt;&#x2F;p&gt;
&lt;p&gt;因此参照表&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;img&#x2F;flash_table.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;del&gt;Flash应为从&lt;code&gt;0x08000000&lt;&#x2F;code&gt;开始，到&lt;code&gt;0x080FFFFF&lt;&#x2F;code&gt;结束。用末尾减去开头，刚好是&lt;code&gt;1024&lt;&#x2F;code&gt;K。&lt;&#x2F;del&gt;&lt;&#x2F;p&gt;
&lt;p&gt;但上述其实不过是对最高配置的介绍，并非所有的STM32F40x都有高达&lt;code&gt;1&lt;&#x2F;code&gt;M的实际Flash大小，具体仍要参照型号。&lt;&#x2F;p&gt;
&lt;p&gt;由于我们的板子的详细型号是STM32F407VET6，因此Flash只有&lt;code&gt;512&lt;&#x2F;code&gt;K。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;srambu-ju&quot;&gt;SRAM布局&lt;&#x2F;h4&gt;
&lt;p&gt;参照第&lt;strong&gt;68&lt;&#x2F;strong&gt;页的描述：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;img&#x2F;SRAM.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;由于我们的板子不存在SRAM3，所以SRAM的起始地址应为&lt;code&gt;0x20000000&lt;&#x2F;code&gt;。Backup SRAM只在特殊的电压条件下才会被调用，&lt;del&gt;因此SRAM的长度应标注为&lt;code&gt;192&lt;&#x2F;code&gt;K&lt;&#x2F;del&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;但在编译时，还应结合板子的整体架构考虑：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;img&#x2F;system_architecture.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在文字描述中高达&lt;code&gt;192&lt;&#x2F;code&gt;K的“系统”SRAM当中其实还包含了只能经由D-bus主线直接与MCU通信的、大小为&lt;code&gt;64&lt;&#x2F;code&gt;K的CCM内存。&lt;&#x2F;p&gt;
&lt;p&gt;因此实际&lt;strong&gt;在编译时可以声明的内存大小&lt;&#x2F;strong&gt;只有&lt;code&gt;192&lt;&#x2F;code&gt; - &lt;code&gt;64&lt;&#x2F;code&gt; = &lt;code&gt;128&lt;&#x2F;code&gt;K。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;esp8266pian&quot;&gt;ESP8266篇&lt;&#x2F;h2&gt;
&lt;p&gt;待续。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;qi-ta-xuan-ze&quot;&gt;其他选择&lt;&#x2F;h2&gt;
&lt;p&gt;STM32CubeIDE 也许是不错的一体化集成开发环境。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;chang-jian-wen-ti&quot;&gt;常见问题&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;0-wei-shen-me-yi-jing-cha-zai-usbshang-liao-dan-lsusbkan-bu-dao-ban-zi&quot;&gt;0. 为什么已经插在USB上了，但&lt;code&gt;lsusb&lt;&#x2F;code&gt;看不到板子？&lt;&#x2F;h3&gt;
&lt;p&gt;可能接错到USB-Slave接口上了。可以用&lt;code&gt;sudo dmesg&lt;&#x2F;code&gt;查看详细日志：
&lt;img src=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;img&#x2F;dmesg_err.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-shi-yong-gdbdiao-shi-shi-chu-xian-nei-cun-cuo-wu&quot;&gt;1. 使用GDB调试时出现内存错误&lt;&#x2F;h3&gt;
&lt;p&gt;如果内存布局设置错误或有严重的编程失误导致内存错误，可能会在OpenOCD输出中看到类似如下报错：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Error: Failed to read memory at 0x2002ffd0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;同时GDB也会反馈类似内容：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x080013aa in cortex_m_rt::HardFault_ (ef=0x0) at src&#x2F;lib.rs:563&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;563             atomic::compiler_fence(Ordering::SeqCst);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;可能板子被锁住：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;img&#x2F;lockup.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;出现这种情况时，请首先&lt;a href=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;#srambu-ju&quot;&gt;确认内存布局正确&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意，更改&lt;code&gt;memory.x&lt;&#x2F;code&gt;文件后需要重新&lt;code&gt;cargo build&lt;&#x2F;code&gt;，这点在The Embedded Rust Book中&lt;a class=&quot;external&quot; rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rust-embedded.org&#x2F;book&#x2F;start&#x2F;hardware.html#configuring&quot;&gt;也有提及&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;另外，建议使用&lt;a href=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;#bian-yi-an-zhuang-openocd&quot;&gt;最新版本的OpenOCD&lt;&#x2F;a&gt;，可能在重新开启OpenOCD进程或烧写程序（GDB的&lt;code&gt;load&lt;&#x2F;code&gt;指令）时自动解锁。&lt;&#x2F;p&gt;
&lt;p&gt;如果仍被锁住，则可按照如下步骤处理：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;开启一个&lt;code&gt;openocd&lt;&#x2F;code&gt;进程与板子连接&lt;&#x2F;li&gt;
&lt;li&gt;在另外一个终端里使用&lt;code&gt;telnet&lt;&#x2F;code&gt;与&lt;code&gt;openocd&lt;&#x2F;code&gt;通讯：&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;telnet&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; localhost&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4444&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;在telnet提示符下尝试解锁：&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stm32f4x unlock 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果顺利的话，会出现如下提示：&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stm32f2x unlocked.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;INFO: a reset or power cycle is required for the new settings to take effect.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;在telnet提示符下继续输入&lt;code&gt;shutdown&lt;&#x2F;code&gt;，然后将板子断电再通电。&lt;&#x2F;li&gt;
&lt;li&gt;如果上述过程无效，尝试在telnet提示符下使用下面的命令彻底擦除Flash存储中的内容：&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stm32f4x mass_erase 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;然后重复第&lt;strong&gt;4&lt;&#x2F;strong&gt;步。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-cargo-buildbao-cuo-cannot-find-linker-script-memory-x&quot;&gt;2. &lt;code&gt;cargo build&lt;&#x2F;code&gt;报错：cannot find linker script memory.x&lt;&#x2F;h3&gt;
&lt;p&gt;无论当前项目是否有子crates、目录如何组织，&lt;code&gt;memory.x&lt;&#x2F;code&gt;必须位于项目的根目录下（和最外层的&lt;code&gt;Cargo.toml&lt;&#x2F;code&gt;同级）&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-4-1&quot;&gt;&lt;a href=&quot;#fn-4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;确实有一种特殊情况可以不提供&lt;code&gt;memory.x&lt;&#x2F;code&gt;文件：项目代码中直接引入了BSC (Board Support Crate)，比如&lt;a class=&quot;external&quot; rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;stm32f3-discovery&quot;&gt;stm32f3-discovery&lt;&#x2F;a&gt;。除此之外，使用属于其他抽象级别的crates都必须为&lt;code&gt;cortex-m-rt&lt;&#x2F;code&gt;的编译提供&lt;code&gt;memory.x&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-5-1&quot;&gt;&lt;a href=&quot;#fn-5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.bigdick.live&#x2F;blog&#x2F;stm32f407-http&#x2F;img&#x2F;dmesg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;这里只看到&lt;code&gt;CMSIS-DAP&lt;&#x2F;code&gt;，没有看到STM32相关的信息。&lt;code&gt;sudo dmesg&lt;&#x2F;code&gt;可以在日志中看到细节： &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;这里文件名不是必需为&lt;code&gt;70-st-link.rules&lt;&#x2F;code&gt;，但建议前缀的数字要大于&lt;code&gt;50&lt;&#x2F;code&gt;，否则有可能覆写操作系统的一些默认规则。
有关&lt;code&gt;udev&lt;&#x2F;code&gt;规则语法，可参照&lt;a class=&quot;external&quot; rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man7&#x2F;udev.7.html&quot;&gt;&lt;code&gt;udev(7)&lt;&#x2F;code&gt;手册&lt;&#x2F;a&gt;。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;头几个sector的大小比较小是因为许多板子并未达到&lt;code&gt;1&lt;&#x2F;code&gt;M的Flash大小，因此只有头几个sector，后面较大的则被舍弃了。&lt;br &#x2F;&gt;
这样的设计使得不同型号的板之间的sector布局尽量保持一致，程序移植的兼容性比较好。 &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-4&quot;&gt;
&lt;p&gt;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&#x2F;issues&#x2F;9537 &lt;a href=&quot;#fr-4-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-5&quot;&gt;
&lt;p&gt;https:&#x2F;&#x2F;docs.rust-embedded.org&#x2F;book&#x2F;start&#x2F;registers.html#memory-mapped-registers &lt;a href=&quot;#fr-5-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">记录从0开始在STM32F407上编写Rust实现HTTP GET。</summary>
        </entry>
</feed>
