<?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>内存管理 on 栈外随记</title>
    <link>https://btio.cn/tags/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</link>
    <description>Recent content in 内存管理 on 栈外随记</description>
    <image>
      <title>栈外随记</title>
      <url>https://btio.cn/images/logo-arong.svg</url>
      <link>https://btio.cn/images/logo-arong.svg</link>
    </image>
    <generator>Hugo</generator>
    <language>zh-CN</language><lastBuildDate>Thu, 06 Aug 2026 08:00:00 +0800</lastBuildDate>
    <atom:link href="https://btio.cn/tags/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>【中科蓝讯】从两次偶发死机，理解 com 区和 bank 区</title>
      <link>https://btio.cn/posts/2026/08/06/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E4%BB%8E%E4%B8%A4%E6%AC%A1%E5%81%B6%E5%8F%91%E6%AD%BB%E6%9C%BA%E7%90%86%E8%A7%A3-com-%E5%8C%BA%E5%92%8C-bank-%E5%8C%BA/</link>
      <pubDate>Thu, 06 Aug 2026 08:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/06/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E4%BB%8E%E4%B8%A4%E6%AC%A1%E5%81%B6%E5%8F%91%E6%AD%BB%E6%9C%BA%E7%90%86%E8%A7%A3-com-%E5%8C%BA%E5%92%8C-bank-%E5%8C%BA/</guid>
      <description>&lt;p&gt;刚接触中科蓝讯 SDK 时，我经常看到函数前面有 &lt;code&gt;AT(.com_text.xxx)&lt;/code&gt;。一开始我只知道照着原有代码写，却不明白它为什么在这里。后来看了资料和工程里的写法，我才认识到：SDK 把代码分区域存放，不同区域的运行方式不一样。&lt;/p&gt;
&lt;p&gt;这篇只是我目前从应用侧整理的一点理解，重点放在看到 &lt;code&gt;AT(...)&lt;/code&gt; 时怎么读。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、com 区和 bank 区有什么区别&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;com 区和 bank 区的存放与运行示意&#34; loading=&#34;lazy&#34; src=&#34;https://btio.cn/images/csdn/163511359/image.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;按照官方资料的说明，芯片上电后，一部分代码会从 Flash 搬到 RAM 里常驻下来，这部分就是 &lt;code&gt;com&lt;/code&gt; 区；剩下的代码继续待在 Flash，用到时才被加载到 &lt;code&gt;bank&lt;/code&gt; 运行区。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;区域&lt;/th&gt;
					&lt;th&gt;简单理解&lt;/th&gt;
					&lt;th&gt;适合放什么&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;com&lt;/code&gt; 区&lt;/td&gt;
					&lt;td&gt;上电后会加载到 RAM，并在运行期间常驻&lt;/td&gt;
					&lt;td&gt;中断函数、实时性要求高的&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;bank&lt;/code&gt; 区&lt;/td&gt;
					&lt;td&gt;代码存在 Flash，运行时按需加载到 bank 运行区&lt;/td&gt;
					&lt;td&gt;大多数普通应用逻辑&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;com&lt;/code&gt; 区的空间有限，所以不要因为更快，就把普通功能都放进去。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、真正要注意的是中断和它调用的函数&lt;/h2&gt;
&lt;p&gt;中断函数和它调到的关键函数，通常需要放在 &lt;code&gt;com&lt;/code&gt; 区。因为中断来了要马上处理，不能等到需要时再去加载代码。&lt;/p&gt;
&lt;p&gt;在工程里看定时和一些中断相关代码时，我能看到类似下面的写法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;AT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com_text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;user_timer_isr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 中断中的处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;实际用的时候，我是先看同模块已有代码的写法，不凭空猜。但照抄还不够——踩过两次坑才知道，光盯着函数本身的 &lt;code&gt;AT&lt;/code&gt;，容易漏掉更深层的依赖。&lt;/p&gt;
&lt;p&gt;第一次是在中断里调了一个普通函数，我给那个函数加了 &lt;code&gt;AT(.com_text.xxx)&lt;/code&gt;，以为这就完事了。结果还是偶发异常。排查后发现，这个函数内部又调了另一个普通函数，那个子函数没加 &lt;code&gt;AT&lt;/code&gt;。中断触发时 CPU 跳到 com 区，执行到嵌套的子函数时，它的代码还在 bank 区没加载进来，一样挂。这件事的风险在于，被调函数可能还调了其他函数，嵌套几层之后很容易漏掉。所以给函数加 &lt;code&gt;AT&lt;/code&gt; 时，得顺着调用链往下检查，确保整条执行路径上的函数都在 com 区。如果调用深度比较大，更稳妥的做法是通过消息转发把逻辑放到其他线程执行，避免在 com 区里越套越深。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
