<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>BootROM on 夜云泊</title>
    <link>https://lifeislife.cn/tags/bootrom/</link>
    <description>feedId:57980998056508425+userId:73222296380546048 Recent content in BootROM on 夜云泊</description>
    <generator>Hugo -- 0.161.1</generator>
    <language>zh</language>
    <lastBuildDate>Sat, 30 Mar 2024 21:38:10 +0000</lastBuildDate>
    <atom:link href="https://lifeislife.cn/tags/bootrom/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>BootROM 中 SPI 如何适配不同厂家的 Flash 芯片</title>
      <link>https://lifeislife.cn/posts/bootrom%E4%B8%ADspi%E5%A6%82%E4%BD%95%E9%80%82%E9%85%8D%E4%B8%8D%E5%90%8C%E5%8E%82%E5%AE%B6%E7%9A%84flash%E8%8A%AF%E7%89%87/</link>
      <pubDate>Sat, 30 Mar 2024 21:38:10 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/bootrom%E4%B8%ADspi%E5%A6%82%E4%BD%95%E9%80%82%E9%85%8D%E4%B8%8D%E5%90%8C%E5%8E%82%E5%AE%B6%E7%9A%84flash%E8%8A%AF%E7%89%87/</guid>
      <description>&lt;h1 id=&#34;问题背景&#34;&gt;问题背景&lt;/h1&gt;
&lt;p&gt;一款 SoC 芯片，会支持多种方式启动，比如从 NAND Flash、SPI Flash、eMMC、USB、UART 启动。对于 SPI Flash 启动，BootROM 需要知道 SPI Flash 的型号、容量、页大小、擦除大小等信息，以便正确读取、写入、擦除 SPI Flash。但是，不同厂家的 SPI Flash，这些参数可能不同，而 ROM 中的代码是无法修改的，并且容量有限，如何以最小的代码量，适配不同厂家的 SPI Flash 呢？&lt;/p&gt;
&lt;h1 id=&#34;spi-开发流程&#34;&gt;SPI 开发流程&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SPI 控制器初始&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SPI 控制器有自己的寄存器，可以配置 SPI 的页，块的擦除时间，是否需要 DMA，是否开启中断，单次读写的大小等等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 SPI 对 Flash 进行配置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;BootROM 的 SPI 支持三种模式：Single、Dual、Quad，这不仅要配置 SPI 本身的寄存器，也需要配置 Flash 的寄存器。配置 Flash 的寄存器就需要使用 SPI 来完成。
&lt;ul&gt;
&lt;li&gt;BootROM 中配置 SPI 控制器的 &lt;code&gt;SPIC_CSR_01&lt;/code&gt; 寄存器的&lt;code&gt;spi_bus_mode&lt;/code&gt; 位可以配置 SPI 的模式；&lt;/li&gt;
&lt;li&gt;查阅 Flash 手册，找到配置总线模式的寄存器以及操作它的命令，如 WINBOND-W25Q128JW 这款 Flash 的配置寄存器为 &lt;code&gt;Status Register-2&lt;/code&gt;，Flash 的寄存器是无法直接读写的，所以需要在 Flash 手册中找到操作这个寄存器的命令，在手册的 Instructions 章节可以找到这款 Flash 的配置命令为 &lt;code&gt;Write Status Register-2&lt;/code&gt;，命令码为 &lt;code&gt;0x31&lt;/code&gt;，只要我们向 Flash 发送 &lt;code&gt;0x31&lt;/code&gt;，就可以配置 Flash 的总线模式了。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2Fe7024b05e381b724d3471744f323de76.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2Fe7024b05e381b724d3471744f323de76.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2F350d91ef1d63ed0c5650e4dfd2c72917.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2F350d91ef1d63ed0c5650e4dfd2c72917.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/li&gt;
&lt;li&gt;如何向 Flash 发送指令？需要将真正要发送的指令写入 SPI 的寄存器&lt;code&gt;SPIC_CSR_06&lt;/code&gt;，该寄存器的各个 Bit 可以配置命令码，命令类型，命令是否有效等信息。我们将之前的命令码&lt;code&gt;0x31&lt;/code&gt;写入到&lt;code&gt;SPIC_CSR_06&lt;/code&gt;的&lt;code&gt;command_code&lt;/code&gt;位，然后将&lt;code&gt;SPIC_CSR_06&lt;/code&gt;的&lt;code&gt;command_type&lt;/code&gt;位设置为&lt;code&gt;write status register&lt;/code&gt;，SPI 就会自动将这些信息发送给 Flash。Flash 接收到命令后，会根据命令码执行配置寄存器的操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SPI 读写 Flash&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;和配置 Flash 总线模式一样，读写 Flash 也需要配置 SPI 控制器的寄存器，以及配置 Flash 的寄存器。SPI 控制器的寄存器配置和配置 Flash 总线模式一样，只是命令码和命令类型不同。稍有不同的是需要先配置好 SPI 寄存器，配置读写的大小以及读写的地址，然后再配置&lt;code&gt;SPIC_CSR_06&lt;/code&gt;。Flash接收到命令后，会根据命令码执行读写操作。主设备只需要读写 Flash 的指定地址即可读写到数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;spi-驱动如何适配不同的-flash&#34;&gt;SPI 驱动如何适配不同的 Flash&lt;/h1&gt;
&lt;p&gt;在开发流程中我们并未考虑不同厂家的 Flash 如何操作，只是关心了 WINBOND-W25Q128JW 这款 Flash 的操作。在操作过程中我们可以发现，不同厂家的 Flash 的操作基本一致，只是命令码、页大小、擦除大小等参数不同。我们只要针对不同的 Flash，配置不同的参数即可。但是，如何知道当前 Flash 的参数呢？这就需要用到 SFDP 了。&lt;/p&gt;
&lt;p&gt;SFDP 是 JEDEC 发布的 JESD216 的一个新标准，目前的版本号是 V1.0。简而言之，SFDP（Serial Flash Discoverable Parameters）就相当于一张存储了 FLASH 部分属性的表，此表是不占用 FLASH 本身的存储空间的。SFDP 中的信息自出厂就被固定，只供读取，开发人员可通过发送操作指令 0x5A 来读取当前 FLASH 的 SFDP 相关内容，这有利于开发人员了解 FLASH 之间的差异，提高开发效率，缩短整个开发周期。&lt;/p&gt;
&lt;p&gt;也就是只要 Flash 研发时遵循了 JESD216 这个标准，我们都可以通过发送 0x5A 这个命令码，去获取Flash相关参数。最为关键的就是其中会保存 Flash 厂商的 ID，当我们获取到 Flash 厂商的 ID 时，我们就可以根据 ID 执行不同的配置操作。&lt;/p&gt;
&lt;p&gt;对于 WINBOND-W25Q128JW 这款 Flash，在数据手册的Feature里就可以看到它是支持 SFDP 的：


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2Fbe54a549cc9266d120b1e2db37d68555.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2Fbe54a549cc9266d120b1e2db37d68555.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h1 id="问题背景">问题背景</h1>
<p>一款 SoC 芯片，会支持多种方式启动，比如从 NAND Flash、SPI Flash、eMMC、USB、UART 启动。对于 SPI Flash 启动，BootROM 需要知道 SPI Flash 的型号、容量、页大小、擦除大小等信息，以便正确读取、写入、擦除 SPI Flash。但是，不同厂家的 SPI Flash，这些参数可能不同，而 ROM 中的代码是无法修改的，并且容量有限，如何以最小的代码量，适配不同厂家的 SPI Flash 呢？</p>
<h1 id="spi-开发流程">SPI 开发流程</h1>
<ul>
<li>
<p>SPI 控制器初始</p>
<ul>
<li>SPI 控制器有自己的寄存器，可以配置 SPI 的页，块的擦除时间，是否需要 DMA，是否开启中断，单次读写的大小等等。</li>
</ul>
</li>
<li>
<p>使用 SPI 对 Flash 进行配置</p>
<ul>
<li>BootROM 的 SPI 支持三种模式：Single、Dual、Quad，这不仅要配置 SPI 本身的寄存器，也需要配置 Flash 的寄存器。配置 Flash 的寄存器就需要使用 SPI 来完成。
<ul>
<li>BootROM 中配置 SPI 控制器的 <code>SPIC_CSR_01</code> 寄存器的<code>spi_bus_mode</code> 位可以配置 SPI 的模式；</li>
<li>查阅 Flash 手册，找到配置总线模式的寄存器以及操作它的命令，如 WINBOND-W25Q128JW 这款 Flash 的配置寄存器为 <code>Status Register-2</code>，Flash 的寄存器是无法直接读写的，所以需要在 Flash 手册中找到操作这个寄存器的命令，在手册的 Instructions 章节可以找到这款 Flash 的配置命令为 <code>Write Status Register-2</code>，命令码为 <code>0x31</code>，只要我们向 Flash 发送 <code>0x31</code>，就可以配置 Flash 的总线模式了。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2Fe7024b05e381b724d3471744f323de76.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2Fe7024b05e381b724d3471744f323de76.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2F350d91ef1d63ed0c5650e4dfd2c72917.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2F350d91ef1d63ed0c5650e4dfd2c72917.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></li>
<li>如何向 Flash 发送指令？需要将真正要发送的指令写入 SPI 的寄存器<code>SPIC_CSR_06</code>，该寄存器的各个 Bit 可以配置命令码，命令类型，命令是否有效等信息。我们将之前的命令码<code>0x31</code>写入到<code>SPIC_CSR_06</code>的<code>command_code</code>位，然后将<code>SPIC_CSR_06</code>的<code>command_type</code>位设置为<code>write status register</code>，SPI 就会自动将这些信息发送给 Flash。Flash 接收到命令后，会根据命令码执行配置寄存器的操作。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>SPI 读写 Flash</p>
<ul>
<li>和配置 Flash 总线模式一样，读写 Flash 也需要配置 SPI 控制器的寄存器，以及配置 Flash 的寄存器。SPI 控制器的寄存器配置和配置 Flash 总线模式一样，只是命令码和命令类型不同。稍有不同的是需要先配置好 SPI 寄存器，配置读写的大小以及读写的地址，然后再配置<code>SPIC_CSR_06</code>。Flash接收到命令后，会根据命令码执行读写操作。主设备只需要读写 Flash 的指定地址即可读写到数据。</li>
</ul>
</li>
</ul>
<h1 id="spi-驱动如何适配不同的-flash">SPI 驱动如何适配不同的 Flash</h1>
<p>在开发流程中我们并未考虑不同厂家的 Flash 如何操作，只是关心了 WINBOND-W25Q128JW 这款 Flash 的操作。在操作过程中我们可以发现，不同厂家的 Flash 的操作基本一致，只是命令码、页大小、擦除大小等参数不同。我们只要针对不同的 Flash，配置不同的参数即可。但是，如何知道当前 Flash 的参数呢？这就需要用到 SFDP 了。</p>
<p>SFDP 是 JEDEC 发布的 JESD216 的一个新标准，目前的版本号是 V1.0。简而言之，SFDP（Serial Flash Discoverable Parameters）就相当于一张存储了 FLASH 部分属性的表，此表是不占用 FLASH 本身的存储空间的。SFDP 中的信息自出厂就被固定，只供读取，开发人员可通过发送操作指令 0x5A 来读取当前 FLASH 的 SFDP 相关内容，这有利于开发人员了解 FLASH 之间的差异，提高开发效率，缩短整个开发周期。</p>
<p>也就是只要 Flash 研发时遵循了 JESD216 这个标准，我们都可以通过发送 0x5A 这个命令码，去获取Flash相关参数。最为关键的就是其中会保存 Flash 厂商的 ID，当我们获取到 Flash 厂商的 ID 时，我们就可以根据 ID 执行不同的配置操作。</p>
<p>对于 WINBOND-W25Q128JW 这款 Flash，在数据手册的Feature里就可以看到它是支持 SFDP 的：


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2Fbe54a549cc9266d120b1e2db37d68555.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/%2F2024%2F03%2F30%2Fbe54a549cc9266d120b1e2db37d68555.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>IIC 协议</title>
      <link>https://lifeislife.cn/posts/iic%E5%8D%8F%E8%AE%AE/</link>
      <pubDate>Fri, 19 Aug 2022 14:16:29 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/iic%E5%8D%8F%E8%AE%AE/</guid>
      <description>&lt;h1 id=&#34;iic-概述&#34;&gt;IIC 概述&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;IIC（Inter-Integrated Circuit）&lt;/strong&gt;，也叫 I2C（Inter-IC Communication）总线，是一种串行通信协议，由 Philips 公司在 1980 年代初开发。IIC 总线用于连接微控制器、传感器和其他集成电路，它具有以下特点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;双线制结构简单：由一条数据线（SDA）和一条时钟线（SCL）组成。&lt;/li&gt;
&lt;li&gt;多主机并行通信：多个 Master 设备可同时接入同一条 IIC 总线上进行数据交换。&lt;/li&gt;
&lt;li&gt;硬件资源占用少：只要两根线就可以连接多个器件。&lt;/li&gt;
&lt;li&gt;数据传输速率快：现代 IIC 总线的最高传输速率可达到 400Kbps。&lt;/li&gt;
&lt;li&gt;低功耗设计：使用者可以通过软件控制设备进入睡眠模式以减少功耗。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;传输协议&#34;&gt;传输协议&lt;/h1&gt;
&lt;h2 id=&#34;写操作&#34;&gt;写操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;主机要发出一个&lt;strong&gt;起始信号&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;主机发出一个&lt;strong&gt;设备地址&lt;/strong&gt;用来确定是往那一个芯片写数据，以及写标记（0）&lt;/li&gt;
&lt;li&gt;从设备回应（用来确定这个设备是香存在，然后就可以传输数据）&lt;/li&gt;
&lt;li&gt;主设备发送一个字节数据给从设备，并等待回应&lt;/li&gt;
&lt;li&gt;每传输一字节故据，接收方要有一个回应信号（确定故据是否接受完成），然后再传输下一个故据。&lt;/li&gt;
&lt;li&gt;数据发送完之后，主机就会发送一个停止信号。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;读操作&#34;&gt;读操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;主机要发出一个&lt;strong&gt;起始信号&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;主机发出一个&lt;strong&gt;设备地址&lt;/strong&gt;用来确定是往那一个芯片读数据，以及读标记（1）&lt;/li&gt;
&lt;li&gt;从设备回应（用来确定这个设备是否存在），然后就可以传输数据&lt;/li&gt;
&lt;li&gt;从设备发送一个字节放据给主设备，并等待回应&lt;/li&gt;
&lt;li&gt;每传输一字节数据，接收方要有一个回应信号（确定数据是否接受完成），然后再传输下一个放据。&lt;/li&gt;
&lt;li&gt;数据发送完之后，主芯片就会发送一个停止信号。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;状态&#34;&gt;状态&lt;/h1&gt;
&lt;h2 id=&#34;空闲状态&#34;&gt;空闲状态&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SCL 和 SDA 都为高电平&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此时各个器件的输出级场效应管均处在截止状态，即释放总线，由两条信号线各自的上拉电阻把电平拉高。&lt;/p&gt;
&lt;h2 id=&#34;起始状态&#34;&gt;起始状态&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/08/19/e9d2b88fa97d66c8a93d089299d6f636.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/08/19/e9d2b88fa97d66c8a93d089299d6f636.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SCL 为高电平，SDA 由高电平变为低电平&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;标志着一次数据传输的开始。起始信号是由主控器主动建立的，在建立该信号之前 I2C 总线必须处于空闲状态。&lt;/p&gt;
&lt;h2 id=&#34;结束状态&#34;&gt;结束状态&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SCL 为高电平，SDA 由低电平变为高电平&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;数据传输状态&#34;&gt;数据传输状态&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SCL 高电平期间，SDL 保持稳定
&lt;ul&gt;
&lt;li&gt;SDL 为高电平表示 1，低电平表示 0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 IIC 总线上传送的每一位数据都有一个时钟脉冲相对应 (或同步控制)，即在 SCL 串行时钟的配合下，数据在 SDA 上从高位向低位依次串行传送每一位的数据。进行数据传送时，在 SCL 呈现高电平期间，SDA 上的电平必须保持稳定，低电平为数据 0，高电平为数据 1。只有在 SCL 为低电平期间，才允许 SDA 上的电平改变状态。下图是 &lt;code&gt;0xaa&lt;/code&gt; 在 IIC 总线上有效传输 (有效传输是指第 9 个时钟的高电平期间，从机给主机反馈了一个有效的应答位 0) 的图示&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/08/19/d851ded7e34114e925809dbcf33fa894.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/08/19/d851ded7e34114e925809dbcf33fa894.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在时序图中，MSB 代表的是 Most Significant Bit（最高位）。它表示二进制数中最左边的一位，也就是最高位。在一个 n 位的二进制数中，最高位的权值为 2^(n-1)。因此，MSB 在时序图中通常用来指示二进制数或数据字的最高位。同理，LSB 代表的是 Least Significant Bit（最低位）。它表示二进制数中最右边的一位，也就是最低位。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;应答状态&#34;&gt;应答状态&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SCL 为高电平，SDA 由高电平变为低电平（上图最后的 ACK 标记）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I2C 总线上的所有数据都是以 8 位字节传送的，发送器 (主机) 每发送一个字节，就在&lt;strong&gt;第 9 个时钟&lt;/strong&gt;脉冲期间释放数据线，由从设备反馈一个应答信号。应答信号为&lt;strong&gt;低电平&lt;/strong&gt;时，规定为&lt;strong&gt;有效应答位&lt;/strong&gt; (ACK 简称应答位)，表示接收器已经成功地接收了该字节；应答信号为&lt;strong&gt;高电平时&lt;/strong&gt;，规定为&lt;strong&gt;非应答位&lt;/strong&gt; (NACK)，一般表示接收器接收该字节没有成功。对于反馈有效应答位 ACK 的要求是，接收器在第 9 个时钟脉冲之前的低电平期间将 &lt;strong&gt;SDA&lt;/strong&gt; 线拉低，并且确保在该&lt;strong&gt;时钟的高电平期间为稳定的低电平&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;以下四种情况 IIC 通信过程中会产生非应答位（NACK）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从机正在处理某些实时的操作无法与主机实现 IIC 通信的时候，从机会给主机反馈一个非应答 (NACK)&lt;/li&gt;
&lt;li&gt;主机发送数据的过程中，从机无法解析发送的数据，从机也会给主机反馈一个非应答位 (NACK)&lt;/li&gt;
&lt;li&gt;主机发送数据的过程中，从机无法再继续接收数据，从机也会给主机反馈一个非应答位 (NACK)&lt;/li&gt;
&lt;li&gt;主机从从机中读取数据的过程中，主机不想再接收数据，主机会给从机反馈一个非应答位 (NACK)，注意，这种情况是主机给从机反馈一个非应答位 (NACK)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;参考资料&#34;&gt;参考资料&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/liujinggang/p/9656358.html&#34;&gt;IIC总线的原理与Verilog实现 - jgliu - 博客园&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/xuyan123/p/14134246.html&#34;&gt;IIC时序分析 - 夏天师妹 - 博客园&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
      <content:encoded><![CDATA[<h1 id="iic-概述">IIC 概述</h1>
<p><strong>IIC（Inter-Integrated Circuit）</strong>，也叫 I2C（Inter-IC Communication）总线，是一种串行通信协议，由 Philips 公司在 1980 年代初开发。IIC 总线用于连接微控制器、传感器和其他集成电路，它具有以下特点：</p>
<ol>
<li>双线制结构简单：由一条数据线（SDA）和一条时钟线（SCL）组成。</li>
<li>多主机并行通信：多个 Master 设备可同时接入同一条 IIC 总线上进行数据交换。</li>
<li>硬件资源占用少：只要两根线就可以连接多个器件。</li>
<li>数据传输速率快：现代 IIC 总线的最高传输速率可达到 400Kbps。</li>
<li>低功耗设计：使用者可以通过软件控制设备进入睡眠模式以减少功耗。</li>
</ol>
<h1 id="传输协议">传输协议</h1>
<h2 id="写操作">写操作</h2>
<ul>
<li>主机要发出一个<strong>起始信号</strong></li>
<li>主机发出一个<strong>设备地址</strong>用来确定是往那一个芯片写数据，以及写标记（0）</li>
<li>从设备回应（用来确定这个设备是香存在，然后就可以传输数据）</li>
<li>主设备发送一个字节数据给从设备，并等待回应</li>
<li>每传输一字节故据，接收方要有一个回应信号（确定故据是否接受完成），然后再传输下一个故据。</li>
<li>数据发送完之后，主机就会发送一个停止信号。</li>
</ul>
<h2 id="读操作">读操作</h2>
<ul>
<li>主机要发出一个<strong>起始信号</strong></li>
<li>主机发出一个<strong>设备地址</strong>用来确定是往那一个芯片读数据，以及读标记（1）</li>
<li>从设备回应（用来确定这个设备是否存在），然后就可以传输数据</li>
<li>从设备发送一个字节放据给主设备，并等待回应</li>
<li>每传输一字节数据，接收方要有一个回应信号（确定数据是否接受完成），然后再传输下一个放据。</li>
<li>数据发送完之后，主芯片就会发送一个停止信号。</li>
</ul>
<h1 id="状态">状态</h1>
<h2 id="空闲状态">空闲状态</h2>
<ul>
<li>SCL 和 SDA 都为高电平</li>
</ul>
<p>此时各个器件的输出级场效应管均处在截止状态，即释放总线，由两条信号线各自的上拉电阻把电平拉高。</p>
<h2 id="起始状态">起始状态</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/08/19/e9d2b88fa97d66c8a93d089299d6f636.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/08/19/e9d2b88fa97d66c8a93d089299d6f636.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<ul>
<li>SCL 为高电平，SDA 由高电平变为低电平</li>
</ul>
<p>标志着一次数据传输的开始。起始信号是由主控器主动建立的，在建立该信号之前 I2C 总线必须处于空闲状态。</p>
<h2 id="结束状态">结束状态</h2>
<ul>
<li>SCL 为高电平，SDA 由低电平变为高电平</li>
</ul>
<h2 id="数据传输状态">数据传输状态</h2>
<ul>
<li>SCL 高电平期间，SDL 保持稳定
<ul>
<li>SDL 为高电平表示 1，低电平表示 0</li>
</ul>
</li>
</ul>
<p>在 IIC 总线上传送的每一位数据都有一个时钟脉冲相对应 (或同步控制)，即在 SCL 串行时钟的配合下，数据在 SDA 上从高位向低位依次串行传送每一位的数据。进行数据传送时，在 SCL 呈现高电平期间，SDA 上的电平必须保持稳定，低电平为数据 0，高电平为数据 1。只有在 SCL 为低电平期间，才允许 SDA 上的电平改变状态。下图是 <code>0xaa</code> 在 IIC 总线上有效传输 (有效传输是指第 9 个时钟的高电平期间，从机给主机反馈了一个有效的应答位 0) 的图示</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/08/19/d851ded7e34114e925809dbcf33fa894.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/08/19/d851ded7e34114e925809dbcf33fa894.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<blockquote>
<p>在时序图中，MSB 代表的是 Most Significant Bit（最高位）。它表示二进制数中最左边的一位，也就是最高位。在一个 n 位的二进制数中，最高位的权值为 2^(n-1)。因此，MSB 在时序图中通常用来指示二进制数或数据字的最高位。同理，LSB 代表的是 Least Significant Bit（最低位）。它表示二进制数中最右边的一位，也就是最低位。</p>
</blockquote>
<h2 id="应答状态">应答状态</h2>
<ul>
<li>SCL 为高电平，SDA 由高电平变为低电平（上图最后的 ACK 标记）</li>
</ul>
<p>I2C 总线上的所有数据都是以 8 位字节传送的，发送器 (主机) 每发送一个字节，就在<strong>第 9 个时钟</strong>脉冲期间释放数据线，由从设备反馈一个应答信号。应答信号为<strong>低电平</strong>时，规定为<strong>有效应答位</strong> (ACK 简称应答位)，表示接收器已经成功地接收了该字节；应答信号为<strong>高电平时</strong>，规定为<strong>非应答位</strong> (NACK)，一般表示接收器接收该字节没有成功。对于反馈有效应答位 ACK 的要求是，接收器在第 9 个时钟脉冲之前的低电平期间将 <strong>SDA</strong> 线拉低，并且确保在该<strong>时钟的高电平期间为稳定的低电平</strong>。</p>
<p>以下四种情况 IIC 通信过程中会产生非应答位（NACK）：</p>
<ul>
<li>从机正在处理某些实时的操作无法与主机实现 IIC 通信的时候，从机会给主机反馈一个非应答 (NACK)</li>
<li>主机发送数据的过程中，从机无法解析发送的数据，从机也会给主机反馈一个非应答位 (NACK)</li>
<li>主机发送数据的过程中，从机无法再继续接收数据，从机也会给主机反馈一个非应答位 (NACK)</li>
<li>主机从从机中读取数据的过程中，主机不想再接收数据，主机会给从机反馈一个非应答位 (NACK)，注意，这种情况是主机给从机反馈一个非应答位 (NACK)</li>
</ul>
<h1 id="参考资料">参考资料</h1>
<ol>
<li><a href="https://www.cnblogs.com/liujinggang/p/9656358.html">IIC总线的原理与Verilog实现 - jgliu - 博客园</a></li>
<li><a href="https://www.cnblogs.com/xuyan123/p/14134246.html">IIC时序分析 - 夏天师妹 - 博客园</a></li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>SPI 协议</title>
      <link>https://lifeislife.cn/posts/spi%E5%8D%8F%E8%AE%AE/</link>
      <pubDate>Tue, 19 Jul 2022 14:23:40 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/spi%E5%8D%8F%E8%AE%AE/</guid>
      <description>&lt;h1 id=&#34;spi-概述&#34;&gt;SPI 概述&lt;/h1&gt;
&lt;p&gt;SPI 是一种同步的、全双工的、高速的串行通信总线。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/19-17-11-68acbe1aebbf2173bbc3401dffd69c5a-20230814191709-b01232.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/19-17-11-68acbe1aebbf2173bbc3401dffd69c5a-20230814191709-b01232.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;4 线制 SPI 四个信号：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SCLK：串行时钟信号，由主设备产生，用于同步数据传输。&lt;/li&gt;
&lt;li&gt;CS：片选信号，由主设备产生，用于选择从设备。&lt;/li&gt;
&lt;li&gt;MOSI：主设备输出，从设备输入，用于主设备向从设备传输数据。&lt;/li&gt;
&lt;li&gt;MISO：主设备输入，从设备输出，用于从设备向主设备传输数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除了四线式 SPI 总线之外，还有三线式 SPI 总线和双线式 SPI 总线。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;四线式 SPI 总线，也称为标准 SPI 总线，由 SCLK、MOSI、MISO 和 SS（Slave Select）四个信号线组成。其中，SCLK 是时钟信号线；MOSI 是主设备向从设备发送数据的信号线；MISO 是从设备向主设备发送数据的信号线；SS 是从设备的片选信号线，用于选择要通信的从设备。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;三线式 SPI 总线将 MOSI 和 MISO 合并为单一的信号线。这种 SPI 总线有一个专门的叫做 MOMI 的信号线，既可以作为主设备向从设备发送数据的信号线，又可以作为从设备向主设备发送数据的信号线。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;双线式 SPI 总线（也称为 MICROWIRE 或 uWire），由一个串行数据线和一个时钟线组成。在这种 SPI 总线上，没有单独的片选信号线，而是使用一个帧选择控制位来选择相应的从设备。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;他们传输速率有差别吗？
是的，SPI 总线的不同类型之间存在传输速率上的差别。一般情况下，四线式 SPI 总线的传输速度最快，而双线式 SPI 总线的传输速度最慢。但具体的传输速度会受到很多因素的影响，例如工作频率、数据线长度等等。如果要在实际应用中选择合适的 SPI 总线类型，需要考虑诸如这些因素的影响，并根据具体情况进行权衡取舍。
SPI 总线的传输速度快慢与其信号线数量有关。双线式 SPI 总线一共只有两条信号线：一个主设备 (Master) 输出时钟信号 (SCLK)，一个主设备通过该信号线读取从设备 (Slave) 的应答信号。而四线式 SPI 总线除了上述两条信号线外，还有两条用于数据传输的信号线：主设备通过 MOSI 信号线向从设备发送数据，从设备则通过 MISO 信号线将数据返回给主设备。由于四线式 SPI 总线有专门的数据传输信号线，故可以通过同时在这两条信号线上传输数据来实现更高的传输速率，从而比双线式 SPI 总线快一些。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;时钟极性和时钟相位&#34;&gt;时钟极性和时钟相位&lt;/h3&gt;
&lt;p&gt;在 SPI 中，主机可以选择时钟极性和时钟相位。在空闲状态期间，CPOL 位设置时钟信号的极性。空闲状态是指传输开始时 CS 为高电平且在向低电平转变的期间，以及传输结束时 CS 为低电平且在向高电平转变的期间。CPHA 位选择时钟相位。根据 CPHA 位的状态，使用时钟上升沿或下降沿来采样和/或移位数据。主机必须根据从机的要求选择时钟极性和时钟相位。根据 CPOL 和 CPHA 位的选择，有四种 SPI 模式可用。表 1 显示了这 4 种 SPI 模式。&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;SPI 模式&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;CPOL(Serial Clock Polarity)&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;CPHA(Serial Clock Phase)&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;空闲状态下的时钟极性&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;采样时的时钟相位&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;移位数据的时钟相位&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;0&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;0&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;0&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;逻辑低电平&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;上升沿&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;下降沿&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;0&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;逻辑低电平&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;下降沿&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;上升沿&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;2&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;高电平&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;下降沿&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;上升沿&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;3&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;1&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;0&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;高电平&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;上升沿&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;下降沿&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;CPOL 和 CPHA 可以通过 SPI 的状态寄存器设置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;显示了四种 SPI 模式下的通信示例。在这些示例中，数据显示在 MOSI 和 MISO 线上。传输的开始和结束用绿色虚线表示，采样边沿用橙色虚线表示，移位边沿用蓝色虚线表示。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-15-5c6c2c600194fb53f85df52262dad7ef-20230815085012-956ab0.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-15-5c6c2c600194fb53f85df52262dad7ef-20230815085012-956ab0.png&#34; alt=&#34;&#34;  title=&#34; SPI 模式 0 ，CPOL=0 ，CPHA=0 ： CLK 空闲状态 =低电平，数据在上升沿采样，并在下降沿移出。&#34; style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;下图给出了 SPI 模式 1 的时序图。在此模式下，时钟极性为 0，表示时钟信号的空闲状态为低电平。此模式下的时钟相位为 1，表示数据在下降沿采样（由橙色虚线显示），并且数据在时钟信号的上升沿移出（由蓝色虚线显示）。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-28-a01e2572490707cc3b3a2cbad4e05533-20230815085026-b1efe3.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-28-a01e2572490707cc3b3a2cbad4e05533-20230815085026-b1efe3.png&#34; alt=&#34;&#34;  title=&#34;SPI 模式 1 ， CPOL = 0 ， CPHA = 1 ： CLK 空闲状态  = 低电平，数据在下降沿采样， 并在上升沿移出。&#34; style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-42-dba0e3a19915b00ed54953a271095f0a-20230815085039-cbaff8.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-42-dba0e3a19915b00ed54953a271095f0a-20230815085039-cbaff8.png&#34; alt=&#34;&#34;  title=&#34;SPI 模式 2 ， CPOL = 1 ， CPHA = 1 ： CLK 空闲状态  = 高电平，数据在下降沿采样， 并在上升沿移出&#34; style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-57-3256fcb2422ad57e875cfbeb87d64b7b-20230815085056-9b7476.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-57-3256fcb2422ad57e875cfbeb87d64b7b-20230815085056-9b7476.png&#34; alt=&#34;&#34;  title=&#34;SPI 模式 3 ， CPOL=1 ， CPHA=0：CLK空闲状态 =高电平，数据在上升沿采样，并在下降沿移出。&#34; style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h1 id=&#34;多从机配置&#34;&gt;多从机配置&lt;/h1&gt;
&lt;h2 id=&#34;标准-spi-模式&#34;&gt;标准 SPI 模式&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-59-19-58306989e27c67dfcffff44c1ed40855-20230815085917-6b0c7d.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-59-19-58306989e27c67dfcffff44c1ed40855-20230815085917-6b0c7d.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;在常规模式下，主机需要为每个从机提供单独的片选信号。一旦主机使能（拉低）片选信号，MOSI/MISO 线上的时钟和数据便可用于所选的从机。如果使能多个片选信号，则 MISO 线上的数据会被破坏，因为主机无法识别哪个从机正在传输数据。&lt;/p&gt;
&lt;p&gt;从上图可以看出，随着从机数量的增加，来自主机的片选线的数量也增加。这会快速增加主机需要提供的输入和输出数量，并限制可以使用的从机数量。可以使用其他技术来增加常规模式下的从机数量，例如使用多路复用器产生片选信号。&lt;/p&gt;
&lt;h2 id=&#34;菊花链模式&#34;&gt;菊花链模式&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/09-00-50-8735cd63c5a6e4f29f2c92bef5391529-20230815090047-fb7f9d.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/09-00-50-8735cd63c5a6e4f29f2c92bef5391529-20230815090047-fb7f9d.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;在菊花链模式下，所有从机的片选信号连接在一起，数据从一个从机传播到下一个从机。在此配置中，所有从机同时接收同一 SPI 时钟。来自主机的数据直接送到第一个从机，该从机将数据提供给下一个从机，依此类推。&lt;/p&gt;
&lt;p&gt;使用该方法时，由于数据是从一个从机传播到下一个从机，所以传输数据所需的时钟周期数与菊花链中的从机位置成比例。为使第 3 个从机能够获得数据，需要 24 个时钟脉冲，而常规 SPI 模式下只需 8 个时钟脉冲。下图显示了时钟周期和通过菊花链的数据传播。并非所有 SPI 器件都支持菊花链模式。请参阅产品数据手册以确认菊花链是否可用。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/10-38-26-69352144e54b0d62f2077c7e94a2a32a-20230815103825-b99e54.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/10-38-26-69352144e54b0d62f2077c7e94a2a32a-20230815103825-b99e54.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h1 id=&#34;spi-实现&#34;&gt;SPI 实现&lt;/h1&gt;
&lt;h1 id=&#34;参考资料&#34;&gt;参考资料&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://www.analog.com/cn/analog-dialogue/articles/introduction-to-spi-interface.html&#34;&gt;SPI 接口简介 | 亚德诺半导体&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jia.je/hardware/2023/04/26/spi/#sd-%E5%8D%A1&#34;&gt;SPI 协议 - 杰哥的{运维，编程，调板子}小笔记&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h1 id="spi-概述">SPI 概述</h1>
<p>SPI 是一种同步的、全双工的、高速的串行通信总线。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/19-17-11-68acbe1aebbf2173bbc3401dffd69c5a-20230814191709-b01232.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/19-17-11-68acbe1aebbf2173bbc3401dffd69c5a-20230814191709-b01232.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>4 线制 SPI 四个信号：</p>
<ul>
<li>SCLK：串行时钟信号，由主设备产生，用于同步数据传输。</li>
<li>CS：片选信号，由主设备产生，用于选择从设备。</li>
<li>MOSI：主设备输出，从设备输入，用于主设备向从设备传输数据。</li>
<li>MISO：主设备输入，从设备输出，用于从设备向主设备传输数据。</li>
</ul>
<p>除了四线式 SPI 总线之外，还有三线式 SPI 总线和双线式 SPI 总线。</p>
<ul>
<li>
<p>四线式 SPI 总线，也称为标准 SPI 总线，由 SCLK、MOSI、MISO 和 SS（Slave Select）四个信号线组成。其中，SCLK 是时钟信号线；MOSI 是主设备向从设备发送数据的信号线；MISO 是从设备向主设备发送数据的信号线；SS 是从设备的片选信号线，用于选择要通信的从设备。</p>
</li>
<li>
<p>三线式 SPI 总线将 MOSI 和 MISO 合并为单一的信号线。这种 SPI 总线有一个专门的叫做 MOMI 的信号线，既可以作为主设备向从设备发送数据的信号线，又可以作为从设备向主设备发送数据的信号线。</p>
</li>
<li>
<p>双线式 SPI 总线（也称为 MICROWIRE 或 uWire），由一个串行数据线和一个时钟线组成。在这种 SPI 总线上，没有单独的片选信号线，而是使用一个帧选择控制位来选择相应的从设备。</p>
</li>
</ul>
<blockquote>
<p>他们传输速率有差别吗？
是的，SPI 总线的不同类型之间存在传输速率上的差别。一般情况下，四线式 SPI 总线的传输速度最快，而双线式 SPI 总线的传输速度最慢。但具体的传输速度会受到很多因素的影响，例如工作频率、数据线长度等等。如果要在实际应用中选择合适的 SPI 总线类型，需要考虑诸如这些因素的影响，并根据具体情况进行权衡取舍。
SPI 总线的传输速度快慢与其信号线数量有关。双线式 SPI 总线一共只有两条信号线：一个主设备 (Master) 输出时钟信号 (SCLK)，一个主设备通过该信号线读取从设备 (Slave) 的应答信号。而四线式 SPI 总线除了上述两条信号线外，还有两条用于数据传输的信号线：主设备通过 MOSI 信号线向从设备发送数据，从设备则通过 MISO 信号线将数据返回给主设备。由于四线式 SPI 总线有专门的数据传输信号线，故可以通过同时在这两条信号线上传输数据来实现更高的传输速率，从而比双线式 SPI 总线快一些。</p>
</blockquote>
<h3 id="时钟极性和时钟相位">时钟极性和时钟相位</h3>
<p>在 SPI 中，主机可以选择时钟极性和时钟相位。在空闲状态期间，CPOL 位设置时钟信号的极性。空闲状态是指传输开始时 CS 为高电平且在向低电平转变的期间，以及传输结束时 CS 为低电平且在向高电平转变的期间。CPHA 位选择时钟相位。根据 CPHA 位的状态，使用时钟上升沿或下降沿来采样和/或移位数据。主机必须根据从机的要求选择时钟极性和时钟相位。根据 CPOL 和 CPHA 位的选择，有四种 SPI 模式可用。表 1 显示了这 4 种 SPI 模式。</p>
<table>
  <thead>
      <tr>
          <th style="text-align: center">SPI 模式</th>
          <th style="text-align: center">CPOL(Serial Clock Polarity)</th>
          <th style="text-align: center">CPHA(Serial Clock Phase)</th>
          <th style="text-align: center">空闲状态下的时钟极性</th>
          <th style="text-align: center">采样时的时钟相位</th>
          <th style="text-align: center">移位数据的时钟相位</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: center">0</td>
          <td style="text-align: center">0</td>
          <td style="text-align: center">0</td>
          <td style="text-align: center">逻辑低电平</td>
          <td style="text-align: center">上升沿</td>
          <td style="text-align: center">下降沿</td>
      </tr>
      <tr>
          <td style="text-align: center">1</td>
          <td style="text-align: center">0</td>
          <td style="text-align: center">1</td>
          <td style="text-align: center">逻辑低电平</td>
          <td style="text-align: center">下降沿</td>
          <td style="text-align: center">上升沿</td>
      </tr>
      <tr>
          <td style="text-align: center">2</td>
          <td style="text-align: center">1</td>
          <td style="text-align: center">1</td>
          <td style="text-align: center">高电平</td>
          <td style="text-align: center">下降沿</td>
          <td style="text-align: center">上升沿</td>
      </tr>
      <tr>
          <td style="text-align: center">3</td>
          <td style="text-align: center">1</td>
          <td style="text-align: center">0</td>
          <td style="text-align: center">高电平</td>
          <td style="text-align: center">上升沿</td>
          <td style="text-align: center">下降沿</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>CPOL 和 CPHA 可以通过 SPI 的状态寄存器设置。</p>
</blockquote>
<p>显示了四种 SPI 模式下的通信示例。在这些示例中，数据显示在 MOSI 和 MISO 线上。传输的开始和结束用绿色虚线表示，采样边沿用橙色虚线表示，移位边沿用蓝色虚线表示。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-15-5c6c2c600194fb53f85df52262dad7ef-20230815085012-956ab0.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-15-5c6c2c600194fb53f85df52262dad7ef-20230815085012-956ab0.png" alt=""  title=" SPI 模式 0 ，CPOL=0 ，CPHA=0 ： CLK 空闲状态 =低电平，数据在上升沿采样，并在下降沿移出。" style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>下图给出了 SPI 模式 1 的时序图。在此模式下，时钟极性为 0，表示时钟信号的空闲状态为低电平。此模式下的时钟相位为 1，表示数据在下降沿采样（由橙色虚线显示），并且数据在时钟信号的上升沿移出（由蓝色虚线显示）。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-28-a01e2572490707cc3b3a2cbad4e05533-20230815085026-b1efe3.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-28-a01e2572490707cc3b3a2cbad4e05533-20230815085026-b1efe3.png" alt=""  title="SPI 模式 1 ， CPOL = 0 ， CPHA = 1 ： CLK 空闲状态  = 低电平，数据在下降沿采样， 并在上升沿移出。" style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-42-dba0e3a19915b00ed54953a271095f0a-20230815085039-cbaff8.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-42-dba0e3a19915b00ed54953a271095f0a-20230815085039-cbaff8.png" alt=""  title="SPI 模式 2 ， CPOL = 1 ， CPHA = 1 ： CLK 空闲状态  = 高电平，数据在下降沿采样， 并在上升沿移出" style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-57-3256fcb2422ad57e875cfbeb87d64b7b-20230815085056-9b7476.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-50-57-3256fcb2422ad57e875cfbeb87d64b7b-20230815085056-9b7476.png" alt=""  title="SPI 模式 3 ， CPOL=1 ， CPHA=0：CLK空闲状态 =高电平，数据在上升沿采样，并在下降沿移出。" style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h1 id="多从机配置">多从机配置</h1>
<h2 id="标准-spi-模式">标准 SPI 模式</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-59-19-58306989e27c67dfcffff44c1ed40855-20230815085917-6b0c7d.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/08-59-19-58306989e27c67dfcffff44c1ed40855-20230815085917-6b0c7d.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>在常规模式下，主机需要为每个从机提供单独的片选信号。一旦主机使能（拉低）片选信号，MOSI/MISO 线上的时钟和数据便可用于所选的从机。如果使能多个片选信号，则 MISO 线上的数据会被破坏，因为主机无法识别哪个从机正在传输数据。</p>
<p>从上图可以看出，随着从机数量的增加，来自主机的片选线的数量也增加。这会快速增加主机需要提供的输入和输出数量，并限制可以使用的从机数量。可以使用其他技术来增加常规模式下的从机数量，例如使用多路复用器产生片选信号。</p>
<h2 id="菊花链模式">菊花链模式</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/09-00-50-8735cd63c5a6e4f29f2c92bef5391529-20230815090047-fb7f9d.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/09-00-50-8735cd63c5a6e4f29f2c92bef5391529-20230815090047-fb7f9d.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>在菊花链模式下，所有从机的片选信号连接在一起，数据从一个从机传播到下一个从机。在此配置中，所有从机同时接收同一 SPI 时钟。来自主机的数据直接送到第一个从机，该从机将数据提供给下一个从机，依此类推。</p>
<p>使用该方法时，由于数据是从一个从机传播到下一个从机，所以传输数据所需的时钟周期数与菊花链中的从机位置成比例。为使第 3 个从机能够获得数据，需要 24 个时钟脉冲，而常规 SPI 模式下只需 8 个时钟脉冲。下图显示了时钟周期和通过菊花链的数据传播。并非所有 SPI 器件都支持菊花链模式。请参阅产品数据手册以确认菊花链是否可用。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/10-38-26-69352144e54b0d62f2077c7e94a2a32a-20230815103825-b99e54.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/10-38-26-69352144e54b0d62f2077c7e94a2a32a-20230815103825-b99e54.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h1 id="spi-实现">SPI 实现</h1>
<h1 id="参考资料">参考资料</h1>
<p><a href="https://www.analog.com/cn/analog-dialogue/articles/introduction-to-spi-interface.html">SPI 接口简介 | 亚德诺半导体</a></p>
<p><a href="https://jia.je/hardware/2023/04/26/spi/#sd-%E5%8D%A1">SPI 协议 - 杰哥的{运维，编程，调板子}小笔记</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>芯片启动过程全解析</title>
      <link>https://lifeislife.cn/posts/%E8%8A%AF%E7%89%87%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B%E5%85%A8%E8%A7%A3%E6%9E%90/</link>
      <pubDate>Sat, 18 Dec 2021 22:32:27 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%8A%AF%E7%89%87%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B%E5%85%A8%E8%A7%A3%E6%9E%90/</guid>
      <description>&lt;p&gt;内容总结自 B 站 Up&lt;a href=&#34;https://www.bilibili.com/video/BV1AN411R7Be/?spm_id_from=333.788.recommend_more_video.1&#34;&gt;【蛋饼嵌入式】我提着鞋带拎自己？嵌入式芯片启动过程全解析，彻底理解 bootloader&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;当你按下电源开关的那一瞬间，第一行代码如何在芯片上运行起来的呢？嵌入式软件代码需要一定的方式烧录到芯片中才能运行，除了物理刻蚀，无论是通讯端口的传输或者调试端口的烧录，都需要驱动程序的支持。所以说是&lt;strong&gt;程序烧录了程序，软件启动了软件&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这就像自己提着自己的鞋带，把自己拎起来。靴子（Boot）,鞋带（Strap），提鞋带（Loader）。这就是&lt;code&gt;Boot Strap Loader&lt;/code&gt;的命名来源。通常称&lt;code&gt;BootLoader&lt;/code&gt;，中文翻译为&lt;strong&gt;自举&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;BootLoader&lt;/code&gt;是芯片最初运行的代码吗？当然不是，其实每一块芯片在出厂时都在其内部的&lt;code&gt;ROM&lt;/code&gt;中，烧录了它最基础的软件。CPU 搬运并运行的第一条代码的默认位置，就在&lt;code&gt;ROM&lt;/code&gt;的地址空间。所以一切的起始都在硬件上。&lt;/p&gt;
&lt;p&gt;以 X86 架构的鼻祖 8086 芯片为例，按下开关的一瞬间，芯片 Reset 引脚接收到了电平跳变，在一连串电路的作用下，代码段寄存器&lt;code&gt;CS&lt;/code&gt;恢复成&lt;code&gt;0XFFFF&lt;/code&gt;，指令指针寄存器&lt;code&gt;IP&lt;/code&gt;恢复成&lt;code&gt;0X0000&lt;/code&gt;，他们组合成 20 位的地址正好等于 ROM 中存放第一条代码的位置。之后取出这里的指令在跳转到别处。&lt;/p&gt;
&lt;p&gt;ARM 架构的芯片也是类似的过程，对于 32 位的芯片，通电后，&lt;code&gt;PC&lt;/code&gt;指针寄存器复位至零地址，随后从中断向量表表头的 reset 向量处获取下一个跳转的地址。这时候的代码已经以二进制形式存储，处理器可以直接搬到自身缓存中运行。有了这部分代码，就能跳转到存放有更多更复杂的代码的地址。执行硬件自检，基本的初始化操作，提供基础的输入输出支持。之后可以将操作系统从外部的存储空间加载到内部。代码就这样接力式的流转起来。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191002002.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191002002.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;所以我们把出厂就写在&lt;code&gt;ROM&lt;/code&gt;里，负责启动后续用户软件的软件，称为&lt;code&gt;Boot ROM&lt;/code&gt;或者&lt;code&gt;ROM Code&lt;/code&gt;。现在不一定是用只读存储器（Read Only Memory），但是至少是一块掉电不易失的存储器，现在主要用&lt;code&gt;EEPROM&lt;/code&gt;，&lt;code&gt;NOR Flash&lt;/code&gt;。我们一般没有权限修改它，但是它也不完全是黑盒，大部分芯片都会有外部启动配置引脚，通常是以拨码快关的形式。对于 PC 机来说，&lt;code&gt;Boot ROM&lt;/code&gt;就是我们常说的&lt;code&gt;BIOS&lt;/code&gt;，它也有启动配置途径。而且提供了交互界面，用于配置部分功能和选择后续的引导设备。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191009985.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191009985.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;除了芯片自带的&lt;code&gt;Boot ROM&lt;/code&gt;，还需要再给自己实际的应用程序，写一个二次引导代码或者 N 次引导代码，用作操作系统，文件系统加载等等。我们所说的&lt;code&gt;Bootloader&lt;/code&gt;时，其实大多数就是这样的二次引导代码。&lt;/p&gt;
&lt;p&gt;这些事其实&lt;code&gt;Boot ROM&lt;/code&gt;它也能做，但是&lt;code&gt;Boot ROM&lt;/code&gt;实现的功能和配置方法不灵活，但是&lt;code&gt;Bootloader&lt;/code&gt;是开发人员可以而完全控制的引导代码。&lt;/p&gt;
&lt;p&gt;在设计&lt;code&gt;Bootloader&lt;/code&gt;时，&lt;code&gt;MCU&lt;/code&gt;的引导步骤就开始和嵌入式 Linux 或者 PC 有所不同。这一定程度与芯片架构所采用的的存储方案有关。&lt;/p&gt;
&lt;p&gt;先来说&lt;code&gt;MCU&lt;/code&gt;，与&lt;code&gt;SOC&lt;/code&gt;相比&lt;code&gt;MCU&lt;/code&gt;的主要特征是单核和或多核同构的微处理器，单核或多核同构，主频 &amp;lt; 1GHz，没有&lt;code&gt;MMU&lt;/code&gt;内存管理单元，只能运行实时操作系统。常见&lt;code&gt;MCU&lt;/code&gt;内核：&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191051828.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191051828.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;程序的主要运行介质为&lt;code&gt;NOR Flash&lt;/code&gt;，因为和&lt;code&gt;RAM&lt;/code&gt;一样有分离的地址线和数据线。并且可以以字节长度精确寻址，所以程序不需要拷贝到&lt;code&gt;RAM&lt;/code&gt;中运行的。&lt;/p&gt;
&lt;p&gt;以英飞凌家的 TC27x 系列 MCU 为例，上电后的默认取址位置是&lt;code&gt;0x8FFF 8000&lt;/code&gt;，这就是他的&lt;code&gt;Boot ROM&lt;/code&gt;在&lt;code&gt;NorFlash&lt;/code&gt;中的地址。并且这块&lt;code&gt;Boot Rom&lt;/code&gt;分为&lt;code&gt;SSW&lt;/code&gt;，&lt;code&gt;BSL&lt;/code&gt;，&lt;code&gt;TF&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191055339.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191055339.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;SSW 每次上电必须运行，他会根据写在&lt;code&gt;program flash&lt;/code&gt;，&lt;code&gt;PFO&lt;/code&gt;地址的前 32byte 中的配置字，来决定&lt;code&gt;SSW&lt;/code&gt;执行完的跳转地址。我们可以选择一个合适的跳转地址，比如&lt;code&gt;0x80000020&lt;/code&gt;，放上自己写的&lt;code&gt;Bootloader&lt;/code&gt;。也可以选择不跳转，运行厂家提供的&lt;code&gt;Bootloader&lt;/code&gt;（BSL）。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MCU&lt;/code&gt;下的&lt;code&gt;Bootloader&lt;/code&gt;主要完成的事情有以下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;关闭看门狗，初始化中断和 trap 向量表，进行时钟和外设初始化，让芯片正常运行起来。&lt;/li&gt;
&lt;li&gt;提供&lt;code&gt;CAN&lt;/code&gt;,&lt;code&gt;UART&lt;/code&gt;, &lt;code&gt;ETH&lt;/code&gt;等用于通讯功能的驱动，能够接收外部数据传输请求。&lt;/li&gt;
&lt;li&gt;提供&lt;code&gt;FLASH&lt;/code&gt;的读写与擦除驱动，设计服务来对通讯端口接收到的更新代码进行校验、存储，以及跳转操作系统或后续应用程序代码。&lt;/li&gt;
&lt;li&gt;如有必要，还会开发一些基础诊断服务，串口交互程序等等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么运行 Linux 的&lt;code&gt;SOC&lt;/code&gt;和 PC 的这一过程有何不同呢。还是先看存储方案，运行嵌入式 Linux 的 SoC。一般将它的操作系统，文件系统和他的应用程序放在&lt;code&gt;nand flash&lt;/code&gt;中。运行代码前，现将代码搬运到&lt;code&gt;SRAM&lt;/code&gt;中，相比&lt;code&gt;MCU&lt;/code&gt;多了一道步骤。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191101930.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191101930.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;对于&lt;code&gt;SOC&lt;/code&gt;的&lt;code&gt;Boot ROM&lt;/code&gt; 和 PC 的&lt;code&gt;BIOS&lt;/code&gt;而言，他们结束运行前的最终任务，是将某些代码从&lt;code&gt;nand flash&lt;/code&gt;搬运到&lt;code&gt;SRAM&lt;/code&gt;中，其中最重要的内容就是&lt;code&gt;Boot Loader&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;而一般&lt;code&gt;SOC&lt;/code&gt;的&lt;code&gt;Bootloader&lt;/code&gt;，又分为&lt;code&gt;SPL&lt;/code&gt;（Secondary Program Loader）和&lt;code&gt;uBOOT&lt;/code&gt;两个阶段。&lt;code&gt;SPL&lt;/code&gt;的 Secondary 就是相对于&lt;code&gt;BootROM&lt;/code&gt;而言，他就像是接力赛中的第二棒选手。&lt;code&gt;SPL&lt;/code&gt;会初始化更大空间的外部&lt;code&gt;DRAM&lt;/code&gt;，再把&lt;code&gt;uBoot&lt;/code&gt;搬运到外部&lt;code&gt;DRAM&lt;/code&gt;中去运行。&lt;code&gt;uBoot&lt;/code&gt;作为第三棒选手，开始运行它的初始化程序。之后再根据系统环境变量，将 OS 内核搬运到外部&lt;code&gt;DRAM&lt;/code&gt;中去运行。OS 再完成根文件系统的加载等等等等。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191116399.gif&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191116399.gif&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>内容总结自 B 站 Up<a href="https://www.bilibili.com/video/BV1AN411R7Be/?spm_id_from=333.788.recommend_more_video.1">【蛋饼嵌入式】我提着鞋带拎自己？嵌入式芯片启动过程全解析，彻底理解 bootloader</a></p>
<p>当你按下电源开关的那一瞬间，第一行代码如何在芯片上运行起来的呢？嵌入式软件代码需要一定的方式烧录到芯片中才能运行，除了物理刻蚀，无论是通讯端口的传输或者调试端口的烧录，都需要驱动程序的支持。所以说是<strong>程序烧录了程序，软件启动了软件</strong>。</p>
<p>这就像自己提着自己的鞋带，把自己拎起来。靴子（Boot）,鞋带（Strap），提鞋带（Loader）。这就是<code>Boot Strap Loader</code>的命名来源。通常称<code>BootLoader</code>，中文翻译为<strong>自举</strong>。</p>
<p><code>BootLoader</code>是芯片最初运行的代码吗？当然不是，其实每一块芯片在出厂时都在其内部的<code>ROM</code>中，烧录了它最基础的软件。CPU 搬运并运行的第一条代码的默认位置，就在<code>ROM</code>的地址空间。所以一切的起始都在硬件上。</p>
<p>以 X86 架构的鼻祖 8086 芯片为例，按下开关的一瞬间，芯片 Reset 引脚接收到了电平跳变，在一连串电路的作用下，代码段寄存器<code>CS</code>恢复成<code>0XFFFF</code>，指令指针寄存器<code>IP</code>恢复成<code>0X0000</code>，他们组合成 20 位的地址正好等于 ROM 中存放第一条代码的位置。之后取出这里的指令在跳转到别处。</p>
<p>ARM 架构的芯片也是类似的过程，对于 32 位的芯片，通电后，<code>PC</code>指针寄存器复位至零地址，随后从中断向量表表头的 reset 向量处获取下一个跳转的地址。这时候的代码已经以二进制形式存储，处理器可以直接搬到自身缓存中运行。有了这部分代码，就能跳转到存放有更多更复杂的代码的地址。执行硬件自检，基本的初始化操作，提供基础的输入输出支持。之后可以将操作系统从外部的存储空间加载到内部。代码就这样接力式的流转起来。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191002002.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191002002.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>所以我们把出厂就写在<code>ROM</code>里，负责启动后续用户软件的软件，称为<code>Boot ROM</code>或者<code>ROM Code</code>。现在不一定是用只读存储器（Read Only Memory），但是至少是一块掉电不易失的存储器，现在主要用<code>EEPROM</code>，<code>NOR Flash</code>。我们一般没有权限修改它，但是它也不完全是黑盒，大部分芯片都会有外部启动配置引脚，通常是以拨码快关的形式。对于 PC 机来说，<code>Boot ROM</code>就是我们常说的<code>BIOS</code>，它也有启动配置途径。而且提供了交互界面，用于配置部分功能和选择后续的引导设备。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191009985.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191009985.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>除了芯片自带的<code>Boot ROM</code>，还需要再给自己实际的应用程序，写一个二次引导代码或者 N 次引导代码，用作操作系统，文件系统加载等等。我们所说的<code>Bootloader</code>时，其实大多数就是这样的二次引导代码。</p>
<p>这些事其实<code>Boot ROM</code>它也能做，但是<code>Boot ROM</code>实现的功能和配置方法不灵活，但是<code>Bootloader</code>是开发人员可以而完全控制的引导代码。</p>
<p>在设计<code>Bootloader</code>时，<code>MCU</code>的引导步骤就开始和嵌入式 Linux 或者 PC 有所不同。这一定程度与芯片架构所采用的的存储方案有关。</p>
<p>先来说<code>MCU</code>，与<code>SOC</code>相比<code>MCU</code>的主要特征是单核和或多核同构的微处理器，单核或多核同构，主频 &lt; 1GHz，没有<code>MMU</code>内存管理单元，只能运行实时操作系统。常见<code>MCU</code>内核：</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191051828.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191051828.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>程序的主要运行介质为<code>NOR Flash</code>，因为和<code>RAM</code>一样有分离的地址线和数据线。并且可以以字节长度精确寻址，所以程序不需要拷贝到<code>RAM</code>中运行的。</p>
<p>以英飞凌家的 TC27x 系列 MCU 为例，上电后的默认取址位置是<code>0x8FFF 8000</code>，这就是他的<code>Boot ROM</code>在<code>NorFlash</code>中的地址。并且这块<code>Boot Rom</code>分为<code>SSW</code>，<code>BSL</code>，<code>TF</code>。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191055339.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191055339.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>SSW 每次上电必须运行，他会根据写在<code>program flash</code>，<code>PFO</code>地址的前 32byte 中的配置字，来决定<code>SSW</code>执行完的跳转地址。我们可以选择一个合适的跳转地址，比如<code>0x80000020</code>，放上自己写的<code>Bootloader</code>。也可以选择不跳转，运行厂家提供的<code>Bootloader</code>（BSL）。</p>
<p><code>MCU</code>下的<code>Bootloader</code>主要完成的事情有以下：</p>
<ul>
<li>关闭看门狗，初始化中断和 trap 向量表，进行时钟和外设初始化，让芯片正常运行起来。</li>
<li>提供<code>CAN</code>,<code>UART</code>, <code>ETH</code>等用于通讯功能的驱动，能够接收外部数据传输请求。</li>
<li>提供<code>FLASH</code>的读写与擦除驱动，设计服务来对通讯端口接收到的更新代码进行校验、存储，以及跳转操作系统或后续应用程序代码。</li>
<li>如有必要，还会开发一些基础诊断服务，串口交互程序等等。</li>
</ul>
<p>那么运行 Linux 的<code>SOC</code>和 PC 的这一过程有何不同呢。还是先看存储方案，运行嵌入式 Linux 的 SoC。一般将它的操作系统，文件系统和他的应用程序放在<code>nand flash</code>中。运行代码前，现将代码搬运到<code>SRAM</code>中，相比<code>MCU</code>多了一道步骤。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191101930.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191101930.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>对于<code>SOC</code>的<code>Boot ROM</code> 和 PC 的<code>BIOS</code>而言，他们结束运行前的最终任务，是将某些代码从<code>nand flash</code>搬运到<code>SRAM</code>中，其中最重要的内容就是<code>Boot Loader</code>。</p>
<p>而一般<code>SOC</code>的<code>Bootloader</code>，又分为<code>SPL</code>（Secondary Program Loader）和<code>uBOOT</code>两个阶段。<code>SPL</code>的 Secondary 就是相对于<code>BootROM</code>而言，他就像是接力赛中的第二棒选手。<code>SPL</code>会初始化更大空间的外部<code>DRAM</code>，再把<code>uBoot</code>搬运到外部<code>DRAM</code>中去运行。<code>uBoot</code>作为第三棒选手，开始运行它的初始化程序。之后再根据系统环境变量，将 OS 内核搬运到外部<code>DRAM</code>中去运行。OS 再完成根文件系统的加载等等等等。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191116399.gif">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112191116399.gif" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
