<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>esp-idf - MCU &amp; FPGA</title>
	<atom:link href="https://mcu.tec.br/tags/esp-idf/feed/" rel="self" type="application/rss+xml" />
	<link>https://mcu.tec.br</link>
	<description>Microcontroladores &#38; FPGA</description>
	<lastBuildDate>Mon, 31 Mar 2025 18:12:29 +0000</lastBuildDate>
	<language>pt-BR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://mcu.tec.br/wp-content/uploads/2025/02/Robo-para-o-site-MCU.tec_.br-512x512-1-150x150.png</url>
	<title>esp-idf - MCU &amp; FPGA</title>
	<link>https://mcu.tec.br</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Introdução ao Linker em Sistemas Embarcados</title>
		<link>https://mcu.tec.br/geral/introducao-ao-linker-em-sistemas-embarcados/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=introducao-ao-linker-em-sistemas-embarcados</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Mon, 31 Mar 2025 18:12:23 +0000</pubDate>
				<category><![CDATA[geral]]></category>
		<category><![CDATA[arquivo ld]]></category>
		<category><![CDATA[esp-idf]]></category>
		<category><![CDATA[esp32]]></category>
		<category><![CDATA[firmware embarcado]]></category>
		<category><![CDATA[ld file]]></category>
		<category><![CDATA[linker]]></category>
		<category><![CDATA[linker ESP32]]></category>
		<category><![CDATA[linker map]]></category>
		<category><![CDATA[linker script]]></category>
		<category><![CDATA[linker STM32]]></category>
		<category><![CDATA[mapeamento de memória]]></category>
		<category><![CDATA[memória flash]]></category>
		<category><![CDATA[memória RAM]]></category>
		<category><![CDATA[memória ROM]]></category>
		<category><![CDATA[partitions.csv]]></category>
		<category><![CDATA[script de linker]]></category>
		<category><![CDATA[sistemas embarcados]]></category>
		<category><![CDATA[stm32]]></category>
		<category><![CDATA[stm32cubeide]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=295</guid>

					<description><![CDATA[<p>Entenda como funciona o linker e os arquivos .ld em sistemas embarcados como STM32 e ESP32. Veja exemplos práticos, o uso do arquivo partitions.csv e aprenda a customizar o mapeamento de memória do seu firmware.</p>
<p>The post <a href="https://mcu.tec.br/geral/introducao-ao-linker-em-sistemas-embarcados/">Introdução ao Linker em Sistemas Embarcados</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">O Linker é uma das etapas mais críticas no processo de construção de um firmware para sistemas embarcados. Sua função é consolidar diversos arquivos de código objeto em um único arquivo executável, organizando como os dados e instruções serão posicionados na memória do microcontrolador. Em arquiteturas como a do <strong>STM32</strong> (baseada em ARM Cortex-M) e do <strong>ESP32</strong> (baseada em Tensilica Xtensa), o controle de onde e como os segmentos de código e dados são alocados é fundamental para o correto funcionamento do sistema. Esse controle é feito por meio de <strong>scripts de Linker (.ld)</strong> e, no caso do ESP32, também com o <strong>arquivo <code>partitions.csv</code></strong>, que define o particionamento da memória Flash.</p>



<h3 class="wp-block-heading"><strong>Objetivo da Seção</strong></h3>



<p class="wp-block-paragraph">Apresentar uma visão geral do papel do Linker no processo de construção de firmware, destacando:</p>



<ul class="wp-block-list">
<li>O que é o Linker e qual sua função;</li>



<li>Como ele é usado para posicionar variáveis e trechos de código em regiões específicas da memória;</li>



<li>A diferença entre seu uso em plataformas STM32 e ESP32;</li>



<li>A importância dos arquivos <code>.ld</code> e <code>partitions.csv</code> no projeto embarcado.</li>
</ul>



<h3 class="wp-block-heading"><strong>Conceito Básico</strong></h3>



<p class="wp-block-paragraph">Durante a compilação, o código-fonte (em C ou C++) é transformado em arquivos objeto <code>.o</code>. O Linker pega esses arquivos e os combina, resolvendo endereços de funções, referências cruzadas entre variáveis globais e posicionando tudo de acordo com o layout de memória definido pelo script <code>.ld</code>. Esse script age como um <strong>mapa da memória</strong>, especificando as regiões onde devem ser colocados:</p>



<ul class="wp-block-list">
<li>Código (<code>.text</code>);</li>



<li>Dados inicializados (<code>.data</code>);</li>



<li>Dados não inicializados (<code>.bss</code>);</li>



<li>Pilha e heap;</li>



<li>Tabelas de vetores de interrupção e memória de inicialização.</li>
</ul>



<h3 class="wp-block-heading"><strong>Plataformas em Destaque</strong></h3>



<ul class="wp-block-list">
<li><strong>STM32</strong>: Usa arquivos <code>.ld</code> customizados que refletem a memória RAM e Flash, com seções bem definidas para bootloaders, vetores de interrupção, código principal, etc.</li>



<li><strong>ESP32</strong>: Usa também arquivos <code>.ld</code>, mas sua complexidade aumenta com a presença de múltiplas CPUs, caches e particionamento de memória Flash definido pelo <code>partitions.csv</code>.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Estrutura de um Arquivo LD: seções e símbolos</strong></h2>



<p class="wp-block-paragraph">O script do Linker, geralmente com extensão <code>.ld</code>, descreve como o firmware será disposto na memória do dispositivo. Ele segue a sintaxe da linguagem de scripts do GNU Linker (<code>ld</code>) e define <strong>regiões de memória física</strong> e a <strong>atribuição de seções do programa</strong> nessas regiões. Essa estrutura garante que o código e os dados sejam colocados em áreas apropriadas da RAM e Flash.</p>



<h3 class="wp-block-heading"><strong>Definindo a Memória</strong></h3>



<p class="wp-block-paragraph">No início do arquivo <code>.ld</code>, define-se o <strong>layout físico da memória</strong> com a diretiva <code>MEMORY</code>. Essa seção especifica os nomes, tamanhos e endereços base da RAM, Flash e outras regiões, como SRAM2 ou CCM no STM32, ou RTC_SLOW na RAM do ESP32.</p>



<p class="wp-block-paragraph"><strong>Exemplo – STM32:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="MEMORY
{
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
  RAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 128K
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">MEMORY</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">FLASH</span><span style="color: #D8DEE9FF"> (rx) </span><span style="color: #88C0D0">:</span><span style="color: #D8DEE9FF"> ORIGIN = 0x08000000, LENGTH = 512K</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">RAM</span><span style="color: #D8DEE9FF"> (xrw)  </span><span style="color: #88C0D0">:</span><span style="color: #D8DEE9FF"> ORIGIN = 0x20000000, LENGTH = 128K</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Exemplo – ESP32:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="MEMORY
{
  iram0_0_seg (RX) : org = 0x40080000, len = 0x20000
  dram0_0_seg (RW) : org = 0x3FFAE000, len = 0x20000
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">MEMORY</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">iram0_0_seg</span><span style="color: #D8DEE9FF"> (RX) </span><span style="color: #88C0D0">:</span><span style="color: #D8DEE9FF"> org = 0x40080000, len = 0x20000</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">dram0_0_seg</span><span style="color: #D8DEE9FF"> (RW) </span><span style="color: #88C0D0">:</span><span style="color: #D8DEE9FF"> org = 0x3FFAE000, len = 0x20000</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading"><strong>Seções Padrão</strong></h3>



<p class="wp-block-paragraph">A diretiva <code>SECTIONS</code> define como as seções do código objeto (geradas pelo compilador) são mapeadas nas regiões de memória definidas anteriormente.</p>



<h4 class="wp-block-heading">Principais seções:</h4>



<ul class="wp-block-list">
<li><code>.isr_vector</code>: Vetor de interrupções (normalmente colocado no início da Flash).</li>



<li><code>.text</code>: Código do programa.</li>



<li><code>.rodata</code>: Dados somente leitura (constantes).</li>



<li><code>.data</code>: Dados inicializados na RAM.</li>



<li><code>.bss</code>: Variáveis globais não inicializadas (zeradas na inicialização).</li>



<li><code>.heap</code> / <code>.stack</code>: Reservas para alocação dinâmica e pilha de execução.</li>
</ul>



<p class="wp-block-paragraph"><strong>Trecho típico:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="SECTIONS
{
  .text :
  {
    KEEP(*(.isr_vector))
    *(.text*)
    *(.rodata*)
  } &gt; FLASH

  .data : AT (ADDR(.text) + SIZEOF(.text))
  {
    *(.data*)
  } &gt; RAM

  .bss :
  {
    *(.bss*)
    *(COMMON)
  } &gt; RAM
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">SECTIONS</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">.text</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">KEEP(*(.isr_vector</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">*(.text*</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">*(.rodata*</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> FLASH</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">.data</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">AT</span><span style="color: #D8DEE9FF"> (ADDR(.text) + SIZEOF</span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">.text</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">*(.data*</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> RAM</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">.bss</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">*(.bss*</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">*(COMMON</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> RAM</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading"><strong>Símbolos Especiais</strong></h3>



<p class="wp-block-paragraph">Os scripts <code>.ld</code> frequentemente definem símbolos que serão usados no código C para indicar, por exemplo, o início e fim da RAM, do stack, ou a posição de carga de dados:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="_end = .;
_estack = ORIGIN(RAM) + LENGTH(RAM);
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">_end</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">.</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">_estack</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">ORIGIN</span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">RAM</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">LENGTH</span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">RAM</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">No código C, podem ser declarados como:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="extern uint32_t _estack;
extern uint32_t _end;
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">extern</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">_estack</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">extern</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">_end</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading"><strong>Observações Importantes</strong></h3>



<ul class="wp-block-list">
<li>A ordem das seções é essencial: o que estiver listado primeiro será posicionado primeiro na memória.</li>



<li>A diretiva <code>KEEP()</code> impede que o Linker remova seções não referenciadas, comum em vetores de interrupção.</li>



<li>A diretiva <code>AT()</code> é usada para indicar onde os dados residem na Flash antes de serem copiados para a RAM.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Diferenças entre os arquivos LD no STM32 e no ESP32</strong></h2>



<p class="wp-block-paragraph">Embora tanto o STM32 quanto o ESP32 utilizem scripts <code>.ld</code> para definir o mapeamento de memória, existem diferenças estruturais e conceituais importantes entre essas plataformas. Essas diferenças são motivadas pelas arquiteturas distintas de hardware, modelos de inicialização e tipos de memória disponíveis.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>STM32 – Arquitetura Simples e Direta</strong></h3>



<p class="wp-block-paragraph">O STM32, baseado na arquitetura ARM Cortex-M, segue uma abordagem linear e previsível no mapeamento de memória. A memória Flash normalmente começa em <code>0x08000000</code>, e a RAM em <code>0x20000000</code>. A posição do vetor de interrupções (reset vector) é crucial, pois a CPU começa a executar a partir desse ponto após o reset.</p>



<p class="wp-block-paragraph"><strong>Características:</strong></p>



<ul class="wp-block-list">
<li>O arquivo <code>.ld</code> do STM32 é quase sempre dividido em <strong>FLASH</strong> e <strong>RAM</strong>;</li>



<li>Contém o vetor de interrupções na primeira posição (<code>.isr_vector</code>);</li>



<li>Define símbolos como <code>_estack</code> para controle da pilha;</li>



<li>Permite personalizações simples para bootloaders ou seções específicas de RAM (como DTCM, SRAM2, CCMRAM, etc.);</li>



<li>Ferramentas como STM32CubeIDE geram <code>.ld</code> automaticamente com base no modelo selecionado.</li>
</ul>



<p class="wp-block-paragraph"><strong>Exemplo típico de layout:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="MEMORY
{
  FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 512K
  RAM   (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">MEMORY</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">FLASH</span><span style="color: #D8DEE9FF"> (rx)  </span><span style="color: #88C0D0">:</span><span style="color: #D8DEE9FF"> ORIGIN = 0x08000000, LENGTH = 512K</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">RAM</span><span style="color: #D8DEE9FF">   (xrw) </span><span style="color: #88C0D0">:</span><span style="color: #D8DEE9FF"> ORIGIN = 0x20000000, LENGTH = 128K</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>ESP32 – Arquitetura Multinível e Particionada</strong></h3>



<p class="wp-block-paragraph">O ESP32 é mais complexo: possui múltiplos tipos de RAM (DRAM, IRAM, RTC RAM), cache externa e bootloader configurável. A memória Flash é externa e <strong>compartilhada entre o bootloader, partições de aplicativo, sistema de arquivos (SPIFFS/FFat) e NVS</strong> (armazenamento não-volátil).</p>



<p class="wp-block-paragraph"><strong>Características:</strong></p>



<ul class="wp-block-list">
<li>Utiliza <strong>vários arquivos <code>.ld</code></strong> para diferentes segmentos (<code>esp32.ld</code>, <code>memory.ld</code>, <code>sections.ld</code>, etc.);</li>



<li>Define múltiplas regiões: <code>iram0</code>, <code>dram0</code>, <code>rtc_slow</code>, <code>rtc_fast</code>, etc.;</li>



<li>Utiliza a diretiva <code>INCLUDE</code> para modularizar o layout;</li>



<li>Integra o conceito de <strong>partições</strong>, definidas no arquivo <code>partitions.csv</code>;</li>



<li>O bootloader da Espressif localiza a partição de aplicação na Flash e carrega o código para a IRAM ou executa diretamente da Flash (via cache).</li>
</ul>



<p class="wp-block-paragraph"><strong>Trecho exemplo de <code>esp32.ld</code>:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="MEMORY
{
  iram0_0_seg : org = 0x40080000, len = 0x20000
  dram0_0_seg : org = 0x3FFAE000, len = 0x20000
  rtc_slow_seg : org = 0x50000000, len = 0x2000
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">MEMORY</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">iram0_0_seg</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">org</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x40080000</span><span style="color: #A3BE8C">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x20000</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">dram0_0_seg</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">org</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x3FFAE000</span><span style="color: #A3BE8C">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x20000</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">rtc_slow_seg</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">org</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x50000000</span><span style="color: #A3BE8C">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">len</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x2000</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Principais Diferenças Resumidas</strong></h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Aspecto</th><th>STM32</th><th>ESP32</th></tr></thead><tbody><tr><td>Arquitetura</td><td>Cortex-M (monocore ou dual core)</td><td>Tensilica Xtensa (dual core + co-processador)</td></tr><tr><td>Memória Flash</td><td>Interna</td><td>Externa via SPI</td></tr><tr><td>RAM</td><td>Linear e simples</td><td>Vários tipos: DRAM, IRAM, RTC RAM</td></tr><tr><td>Arquivo <code>.ld</code></td><td>Simples, único</td><td>Fragmentado, com includes</td></tr><tr><td>Particionamento</td><td>Manual (caso de bootloaders)</td><td>Definido via <code>partitions.csv</code></td></tr><tr><td>Bootloader</td><td>Opcional ou fixo</td><td>Obrigatório e configurável</td></tr></tbody></table></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Entendendo o partitions.csv no ESP32</strong></h2>



<h3 class="wp-block-heading"><strong>Resumo</strong></h3>



<p class="wp-block-paragraph">O arquivo <code>partitions.csv</code> é um componente essencial nos projetos com ESP32. Ele define como a memória Flash externa será <strong>particionada</strong> para armazenar diferentes partes do firmware, como o bootloader, a aplicação principal, o sistema de arquivos (SPIFFS, FATFS, LittleFS), armazenamento de chaves criptográficas, dados de calibragem de RF, entre outros. É o que garante que o firmware saiba onde cada bloco de dados deve ser gravado e lido na memória externa.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>O que é o <code>partitions.csv</code>?</strong></h3>



<p class="wp-block-paragraph">É um arquivo de texto, em formato <strong>CSV (Comma-Separated Values)</strong>, que define as partições da Flash para uso pelo bootloader e sistema operacional (no caso do ESP-IDF). Ele é convertido em um binário de tabela de partições que o bootloader carrega durante a inicialização.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Formato do Arquivo</strong></h3>



<p class="wp-block-paragraph">Cada linha do <code>partitions.csv</code> define uma partição com os seguintes campos:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="nome, tipo, subtipo, endereço, tamanho, flags
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">nome,</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">tipo,</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">subtipo,</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">endereço,</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">tamanho,</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">flags</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Exemplo comum:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="# Nome      Tipo     Subtipo  Endereço   Tamanho    Flags
nvs         data     nvs      0x9000     0x5000
otadata     data     ota      0xe000     0x2000
app0        app      ota_0    0x10000    1M
app1        app      ota_1    0x110000   1M
spiffs      data     spiffs   0x210000   0xF0000
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88"># Nome      Tipo     Subtipo  Endereço   Tamanho    Flags</span></span>
<span class="line"><span style="color: #88C0D0">nvs</span><span style="color: #D8DEE9FF">         </span><span style="color: #A3BE8C">data</span><span style="color: #D8DEE9FF">     </span><span style="color: #A3BE8C">nvs</span><span style="color: #D8DEE9FF">      </span><span style="color: #B48EAD">0x9000</span><span style="color: #D8DEE9FF">     </span><span style="color: #B48EAD">0x5000</span></span>
<span class="line"><span style="color: #88C0D0">otadata</span><span style="color: #D8DEE9FF">     </span><span style="color: #A3BE8C">data</span><span style="color: #D8DEE9FF">     </span><span style="color: #A3BE8C">ota</span><span style="color: #D8DEE9FF">      </span><span style="color: #B48EAD">0xe000</span><span style="color: #D8DEE9FF">     </span><span style="color: #B48EAD">0x2000</span></span>
<span class="line"><span style="color: #88C0D0">app0</span><span style="color: #D8DEE9FF">        </span><span style="color: #A3BE8C">app</span><span style="color: #D8DEE9FF">      </span><span style="color: #A3BE8C">ota_0</span><span style="color: #D8DEE9FF">    </span><span style="color: #B48EAD">0x10000</span><span style="color: #D8DEE9FF">    </span><span style="color: #B48EAD">1</span><span style="color: #A3BE8C">M</span></span>
<span class="line"><span style="color: #88C0D0">app1</span><span style="color: #D8DEE9FF">        </span><span style="color: #A3BE8C">app</span><span style="color: #D8DEE9FF">      </span><span style="color: #A3BE8C">ota_1</span><span style="color: #D8DEE9FF">    </span><span style="color: #B48EAD">0x110000</span><span style="color: #D8DEE9FF">   </span><span style="color: #B48EAD">1</span><span style="color: #A3BE8C">M</span></span>
<span class="line"><span style="color: #88C0D0">spiffs</span><span style="color: #D8DEE9FF">      </span><span style="color: #A3BE8C">data</span><span style="color: #D8DEE9FF">     </span><span style="color: #A3BE8C">spiffs</span><span style="color: #D8DEE9FF">   </span><span style="color: #B48EAD">0x210000</span><span style="color: #D8DEE9FF">   </span><span style="color: #B48EAD">0xF0000</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Campos Explicados</strong></h3>



<ul class="wp-block-list">
<li><strong>nome</strong>: Identificador da partição (pode ser usado no código C, por exemplo para montar SPIFFS).</li>



<li><strong>tipo</strong>:
<ul class="wp-block-list">
<li><code>app</code>: usado para partições de firmware.</li>



<li><code>data</code>: para armazenamento persistente (ex: NVS, SPIFFS).</li>
</ul>
</li>



<li><strong>subtipo</strong>:
<ul class="wp-block-list">
<li><code>factory</code>, <code>ota_0</code>, <code>ota_1</code>: partições de aplicação.</li>



<li><code>nvs</code>, <code>spiffs</code>, <code>fat</code>, <code>ota</code>, etc.: tipos específicos de dados.</li>
</ul>
</li>



<li><strong>endereço</strong>: onde na memória Flash essa partição começa (em hexadecimal).</li>



<li><strong>tamanho</strong>: em bytes ou usando sufixos (<code>K</code>, <code>M</code>).</li>



<li><strong>flags</strong>: parâmetros opcionais (ex: <code>encrypted</code> para criptografia).</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Como o partitions.csv é usado</strong></h3>



<ol class="wp-block-list">
<li>Durante a <strong>compilação</strong>, o arquivo é processado e gera um binário chamado <code>partition_table.bin</code>.</li>



<li>Durante a <strong>gravação (flash)</strong>, esse binário é gravado em um endereço fixo (tipicamente <code>0x8000</code>).</li>



<li>Durante o <strong>boot</strong>, o bootloader do ESP32 lê essa tabela para saber onde está cada partição.</li>



<li>No <strong>código</strong>, você pode montar sistemas de arquivos ou acessar partições diretamente com base nos nomes definidos no CSV.</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Customização</strong></h3>



<p class="wp-block-paragraph">Você pode modificar o <code>partitions.csv</code> para incluir, por exemplo:</p>



<ul class="wp-block-list">
<li>Mais partições OTA para atualizações em lote;</li>



<li>Uma partição para armazenamento FAT montado via <code>esp_vfs_fat_mount</code>;</li>



<li>Uma partição para arquivos estáticos com LittleFS;</li>



<li>Tamanhos reduzidos para aplicações mínimas.</li>
</ul>



<p class="wp-block-paragraph"><strong>Exemplo com FAT:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="storage     data     fat      0x300000   512K
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">storage</span><span style="color: #D8DEE9FF">     </span><span style="color: #A3BE8C">data</span><span style="color: #D8DEE9FF">     </span><span style="color: #A3BE8C">fat</span><span style="color: #D8DEE9FF">      </span><span style="color: #B48EAD">0x300000</span><span style="color: #D8DEE9FF">   </span><span style="color: #B48EAD">512</span><span style="color: #A3BE8C">K</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Estratégias de Construção de Arquivos LD: práticas e ferramentas</strong></h2>



<h3 class="wp-block-heading"><strong>Resumo</strong></h3>



<p class="wp-block-paragraph">A criação e manutenção de arquivos <code>.ld</code> pode ser feita manualmente ou gerenciada por ferramentas automáticas. Em sistemas embarcados, a escolha da estratégia depende da complexidade da aplicação, do ambiente de desenvolvimento e da necessidade de controle sobre o uso da memória. Nesta seção, exploramos como construir e adaptar arquivos de Linker para STM32 e ESP32, além das ferramentas que auxiliam no processo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Construção Manual de Arquivos <code>.ld</code></strong></h3>



<p class="wp-block-paragraph">A escrita manual é útil em projetos onde se deseja controle total sobre a organização de memória — especialmente para bootloaders, realocação de código crítico em RAM, ou para usar áreas especiais como DTCM, CCM ou RTC.</p>



<p class="wp-block-paragraph"><strong>Dicas práticas:</strong></p>



<ul class="wp-block-list">
<li>Sempre comece definindo corretamente as regiões com <code>MEMORY</code>.</li>



<li>Use <code>SECTIONS</code> para mapear precisamente o conteúdo dos binários.</li>



<li>Defina símbolos auxiliares (<code>_end</code>, <code>_stack_start</code>) para controle no código C.</li>



<li>Use <code>KEEP()</code> para evitar que o Linker remova trechos importantes como vetores de interrupção.</li>



<li>Comente abundantemente o arquivo <code>.ld</code> — erros silenciosos podem causar falhas difíceis de depurar.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Uso de Ferramentas:</strong></h3>



<h4 class="wp-block-heading"><strong>Para STM32:</strong></h4>



<ul class="wp-block-list">
<li><strong>STM32CubeIDE / STM32CubeMX</strong>:
<ul class="wp-block-list">
<li>Gera automaticamente arquivos <code>.ld</code> com base no modelo do microcontrolador selecionado.</li>



<li>Permite configuração de áreas específicas de memória (ex: RAM2, CCMRAM).</li>



<li>Reorganiza o linker script ao incluir bibliotecas HAL ou FreeRTOS.</li>
</ul>
</li>



<li><strong>GNU Arm Toolchain (<code>arm-none-eabi-ld</code>)</strong>:
<ul class="wp-block-list">
<li>O script <code>.ld</code> é passado na linha de comando usando <code>-T</code>.</li>



<li>Pode ser usado em Makefiles ou CMake para projetos personalizados.</li>
</ul>
</li>
</ul>



<h4 class="wp-block-heading"><strong>Para ESP32:</strong></h4>



<ul class="wp-block-list">
<li><strong>ESP-IDF</strong>:
<ul class="wp-block-list">
<li>Utiliza um conjunto modular de scripts <code>.ld</code> organizados em:
<ul class="wp-block-list">
<li><code>memory.ld</code>: define as regiões de memória disponíveis.</li>



<li><code>sections.ld</code>: organiza onde o código e dados são colocados.</li>



<li><code>esp32.ld</code>: script de entrada que inclui os anteriores.</li>
</ul>
</li>



<li>Permite criar <strong>fragmentos de linker (<code>ld</code> fragments)</strong> no diretório do componente para colocar variáveis em regiões específicas, como IRAM.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph"><strong>Exemplo de fragmento:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="myvar (noinit) : ALIGN(4)
{
  _myvar_start = .;
  KEEP(*(.myvar_section))
  _myvar_end = .;
} &gt; DRAM
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">myvar</span><span style="color: #D8DEE9FF"> (noinit) </span><span style="color: #88C0D0">:</span><span style="color: #D8DEE9FF"> ALIGN</span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">4</span><span style="color: #ECEFF4">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">_myvar_start</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">.</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">KEEP(*(.myvar_section</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">_myvar_end</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">.</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> DRAM</span></span>
<span class="line"></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>idf.py linkmap</strong>:
<ul class="wp-block-list">
<li>Gera o mapa de ligação (<code>.map</code>) detalhado, útil para depuração de problemas de alocação de memória.</li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Boas Práticas</strong></h3>



<ul class="wp-block-list">
<li>Sempre gere e revise o <strong>mapa de ligação (<code>.map</code>)</strong> após compilar. Ele mostra o endereço final de cada seção.</li>



<li>Valide o tamanho das regiões para evitar sobreposição.</li>



<li>Em projetos com <strong>OTA</strong>, certifique-se de que as partições app0/app1 não ultrapassem o tamanho máximo.</li>



<li>Use <code>ASSERT()</code> no script <code>.ld</code> para verificar restrições em tempo de link:</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="ASSERT(SIZEOF(.data) < 0x2000, &quot;Data section too big!&quot;)
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">ASSERT(SIZEOF(.data</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> 0x2000, </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Data section too big!</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Casos Práticos: Customizando o Linker para necessidades reais</strong></h2>



<h3 class="wp-block-heading"><strong>Resumo</strong></h3>



<p class="wp-block-paragraph">Customizar o script de Linker permite criar soluções otimizadas para aplicações embarcadas que demandam desempenho, economia de energia ou acesso rápido à memória. A seguir, são apresentados exemplos reais de customizações em projetos com STM32 e ESP32, incluindo alocação de variáveis em regiões específicas, execução de código diretamente na RAM, buffers persistentes e uso de seções noinit.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Executar código diretamente na RAM (STM32)</strong></h3>



<p class="wp-block-paragraph">Para funções críticas em tempo real — como interrupções com baixa latência — pode ser necessário colocá-las na RAM, onde a execução é mais rápida que na Flash.</p>



<p class="wp-block-paragraph"><strong>Etapas:</strong></p>



<ol class="wp-block-list">
<li>Criar uma seção <code>.ramfunc</code> no script:</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code=".ramfunc :
{
  *(.ramfunc*)
} &gt; RAM
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">.ramfunc</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">:</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">*(.ramfunc*</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> RAM</span></span>
<span class="line"></span></code></pre></div>



<ol start="2" class="wp-block-list">
<li>Declarar a função no código com atributo:</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="__attribute__((section(&quot;.ramfunc&quot;))) void critical_ISR(void) {
  // Código de alta prioridade
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">__attribute__((section(</span><span style="color: #88C0D0">&quot;.ramfunc&quot;</span><span style="color: #D8DEE9FF">))) void critical_ISR</span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">void</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">//</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">Código</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">de</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">alta</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">prioridade</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<ol start="3" class="wp-block-list">
<li>(Opcional) Garantir cópia da Flash para RAM durante a inicialização usando <code>AT()</code> e símbolos auxiliares para copiar os dados.</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>2Criar buffers fixos em local específico da RAM (ESP32 e STM32)</strong></h3>



<p class="wp-block-paragraph">Se você precisa garantir que um buffer de DMA fique em uma região não cacheada da memória (ou alinhada), é possível forçar sua posição.</p>



<p class="wp-block-paragraph"><strong>ESP32 – usando fragmento de linker:</strong></p>



<ol class="wp-block-list">
<li>Crie um arquivo <code>linker_fragment.ld</code> no componente:</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="__dma_buffer_start = .;
.dma_buffer (NOLOAD):
{
  . = ALIGN(32);
  KEEP(*(.dma_buffer))
  . = ALIGN(32);
} &gt; DRAM
__dma_buffer_end = .;
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">__dma_buffer_start</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">.</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">.dma_buffer</span><span style="color: #D8DEE9FF"> (NOLOAD):</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">.</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">ALIGN</span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">32</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">KEEP(*(.dma_buffer</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">.</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">ALIGN</span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">32</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> DRAM</span></span>
<span class="line"><span style="color: #88C0D0">__dma_buffer_end</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #A3BE8C">.</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<ol start="2" class="wp-block-list">
<li>No código:</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="__attribute__((section(&quot;.dma_buffer&quot;))) uint8_t dma_rx[256];
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">__attribute__((section(</span><span style="color: #88C0D0">&quot;.dma_buffer&quot;</span><span style="color: #D8DEE9FF">))) uint8_t dma_rx</span><span style="color: #ECEFF4">[</span><span style="color: #B48EAD">256</span><span style="color: #ECEFF4">]</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>3. Buffer persistente entre resets (seção <code>.noinit</code>)</strong></h3>



<p class="wp-block-paragraph">A seção <code>.noinit</code> impede que variáveis sejam zeradas na inicialização. Isso é útil para armazenar dados temporários entre resets, watchdogs ou soft reboots.</p>



<p class="wp-block-paragraph"><strong>Script LD:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code=".noinit (NOLOAD):
{
  *(.noinit*)
} &gt; RAM
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">.noinit</span><span style="color: #D8DEE9FF"> (NOLOAD):</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">*(.noinit*</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> RAM</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Código C:</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="__attribute__((section(&quot;.noinit&quot;))) uint32_t retained_counter;
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">__attribute__((section(</span><span style="color: #88C0D0">&quot;.noinit&quot;</span><span style="color: #D8DEE9FF">))) uint32_t retained_counter</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Importante: você é responsável por inicializar essa variável, pois o C startup não o fará.</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>4. Espaço reservado para bootloader ou firmware OTA</strong></h3>



<p class="wp-block-paragraph">Em projetos com bootloaders, você pode reservar o início da Flash para ele e mover o início da aplicação:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="MEMORY
{
  BOOTLOADER (rx) : ORIGIN = 0x08000000, LENGTH = 16K
  APP_FLASH  (rx) : ORIGIN = 0x08004000, LENGTH = 496K
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">MEMORY</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">BOOTLOADER</span><span style="color: #D8DEE9FF"> (rx) </span><span style="color: #88C0D0">:</span><span style="color: #D8DEE9FF"> ORIGIN = 0x08000000, LENGTH = 16K</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">APP_FLASH</span><span style="color: #D8DEE9FF">  (rx) </span><span style="color: #88C0D0">:</span><span style="color: #D8DEE9FF"> ORIGIN = 0x08004000, LENGTH = 496K</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">E ajustar o início da seção <code>.text</code> para a nova região <code>APP_FLASH</code>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>5. Dividindo a RAM em blocos com finalidades distintas</strong></h3>



<p class="wp-block-paragraph">No STM32 com RAMs separadas (SRAM1, SRAM2), você pode mover buffers grandes para a RAM auxiliar:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="MEMORY
{
  RAM1 (xrw): ORIGIN = 0x20000000, LENGTH = 96K
  RAM2 (xrw): ORIGIN = 0x20018000, LENGTH = 32K
}

.bigbuffers (NOLOAD):
{
  *(.bigbuffer*)
} &gt; RAM2
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">MEMORY</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">RAM1</span><span style="color: #D8DEE9FF"> (xrw): ORIGIN = 0x20000000, LENGTH = 96K</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">RAM2</span><span style="color: #D8DEE9FF"> (xrw): ORIGIN = 0x20018000, LENGTH = 32K</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #88C0D0">.bigbuffers</span><span style="color: #D8DEE9FF"> (NOLOAD):</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">*(.bigbuffer*</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> RAM2</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Esses exemplos ilustram o poder e a flexibilidade dos scripts de Linker quando bem utilizados. Customizá-los pode ser a chave para alcançar desempenho, estabilidade e segurança em sistemas embarcados críticos.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Considerações Finais e Dicas de Diagnóstico</strong></h2>



<p class="wp-block-paragraph">A compreensão e personalização de scripts de Linker são habilidades essenciais para engenheiros de sistemas embarcados. Erros nesse estágio podem resultar em falhas silenciosas, corrupção de dados, mau uso de memória e comportamento imprevisível do firmware. Esta seção final destaca boas práticas, armadilhas comuns e ferramentas úteis para diagnóstico e validação do layout de memória.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Boas Práticas ao Trabalhar com <code>.ld</code></strong></h3>



<ul class="wp-block-list">
<li><strong>Comente extensivamente</strong> cada bloco do script para documentar a intenção de uso de cada região.</li>



<li><strong>Use símbolos nomeados</strong> (_start, _end, <em>stack_top</em>) para facilitar o acesso no código C.</li>



<li><strong>Divida responsabilidades</strong> em arquivos menores com <code>INCLUDE</code> (usado amplamente no ESP-IDF).</li>



<li><strong>Crie seções específicas</strong> para dados críticos, buffers, código de interrupção ou dados de boot.</li>



<li><strong>Teste variações de layout</strong> com segurança em projetos de bootloader + aplicação OTA.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Validação com o Arquivo <code>.map</code></strong></h3>



<p class="wp-block-paragraph">Após a compilação, o GCC gera um arquivo de <strong>mapa de ligação (<code>.map</code>)</strong>, contendo o endereço real de cada símbolo, função e variável alocada.</p>



<p class="wp-block-paragraph"><strong>Dicas para leitura do <code>.map</code>:</strong></p>



<ul class="wp-block-list">
<li>Verifique se há sobreposição entre seções;</li>



<li>Confirme se buffers grandes foram realmente colocados em RAM auxiliar;</li>



<li>Localize variáveis em <code>.bss</code> que estão ocupando muito espaço;</li>



<li>Confirme se a tabela de interrupções foi posicionada corretamente (ex: início da Flash).</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Uso de ASSERTs no Linker</strong></h3>



<p class="wp-block-paragraph">Para evitar erros silenciosos, você pode usar <code>ASSERT()</code> no script <code>.ld</code> para impor limites:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="ASSERT(SIZEOF(.data) <= 0x2000, &quot;Erro: a seção .data ultrapassou o limite da RAM!&quot;)
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">ASSERT(SIZEOF(.data</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF">= 0x2000, </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro: a seção .data ultrapassou o limite da RAM!</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Isso impede que a compilação gere um firmware que vá ultrapassar o espaço físico disponível.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Ferramentas de Apoio</strong></h3>



<ul class="wp-block-list">
<li><strong>objdump (<code>arm-none-eabi-objdump -h</code>)</strong>: mostra as seções e onde foram colocadas.</li>



<li><strong>nm (<code>arm-none-eabi-nm</code>)</strong>: lista símbolos com endereços — útil para variáveis específicas.</li>



<li><strong>size (<code>arm-none-eabi-size</code>)</strong>: resume o tamanho das seções <code>.text</code>, <code>.data</code> e <code>.bss</code>.</li>



<li><strong>idf.py size-components</strong> (ESP32): mostra quanto cada componente ocupa na Flash/RAM.</li>



<li><strong>STM32CubeIDE</strong>: gera visualizações gráficas do uso de memória, além de adaptar o linker automaticamente.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Armadilhas Comuns</strong></h3>



<ul class="wp-block-list">
<li>Esquecer de alinhar buffers de DMA (pode causar falha silenciosa).</li>



<li>Colocar código na IRAM sem definir corretamente as seções no ESP32.</li>



<li>Deixar variáveis grandes na <code>.data</code> (copiadas da Flash para a RAM, consumindo tempo e espaço).</li>



<li>Não usar <code>NOLOAD</code> em seções como <code>.noinit</code>, resultando em perda de dados após o reset.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Conclusão</strong></h3>



<p class="wp-block-paragraph">Scripts de Linker não são apenas “detalhes técnicos”, mas componentes essenciais que controlam como o firmware funciona na prática. Dominar sua estrutura, lógica e sintaxe permite que você construa sistemas mais rápidos, estáveis e confiáveis — explorando ao máximo o hardware disponível, seja no robusto STM32 ou no versátil ESP32.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/><p>The post <a href="https://mcu.tec.br/geral/introducao-ao-linker-em-sistemas-embarcados/">Introdução ao Linker em Sistemas Embarcados</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">295</post-id>	</item>
		<item>
		<title>Introdução ao ESP-Modbus com ESP-IDF</title>
		<link>https://mcu.tec.br/protoclos/introducao-ao-esp-modbus-com-esp-idf/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=introducao-ao-esp-modbus-com-esp-idf</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Sat, 28 Dec 2024 04:57:34 +0000</pubDate>
				<category><![CDATA[Modbus]]></category>
		<category><![CDATA[protocolos]]></category>
		<category><![CDATA[API Modbus]]></category>
		<category><![CDATA[atuadores Modbus]]></category>
		<category><![CDATA[automação industrial]]></category>
		<category><![CDATA[automação residencial]]></category>
		<category><![CDATA[coils]]></category>
		<category><![CDATA[comunicação mestre-escravo]]></category>
		<category><![CDATA[comunicação serial]]></category>
		<category><![CDATA[comunicação TCP/IP]]></category>
		<category><![CDATA[configuração ESP32]]></category>
		<category><![CDATA[configuração Modbus]]></category>
		<category><![CDATA[controle de atuadores]]></category>
		<category><![CDATA[controle remoto]]></category>
		<category><![CDATA[diagnóstico Modbus]]></category>
		<category><![CDATA[dicionário de dados Modbus]]></category>
		<category><![CDATA[dispositivos industriais.]]></category>
		<category><![CDATA[escravo Modbus]]></category>
		<category><![CDATA[esp-idf]]></category>
		<category><![CDATA[ESP-Modbus]]></category>
		<category><![CDATA[esp32]]></category>
		<category><![CDATA[exemplos Modbus]]></category>
		<category><![CDATA[FreeModbus]]></category>
		<category><![CDATA[holding registers]]></category>
		<category><![CDATA[input registers]]></category>
		<category><![CDATA[integração industrial]]></category>
		<category><![CDATA[mestre Modbus]]></category>
		<category><![CDATA[Modbus ASCII]]></category>
		<category><![CDATA[Modbus RTU]]></category>
		<category><![CDATA[Modbus TCP/IP]]></category>
		<category><![CDATA[monitoramento de sensores]]></category>
		<category><![CDATA[protocolos de comunicação]]></category>
		<category><![CDATA[rede Modbus]]></category>
		<category><![CDATA[redes industriais]]></category>
		<category><![CDATA[registro Modbus]]></category>
		<category><![CDATA[registros de entrada]]></category>
		<category><![CDATA[RS-485]]></category>
		<category><![CDATA[SCADA]]></category>
		<category><![CDATA[sensores Modbus]]></category>
		<category><![CDATA[sistemas embarcados]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=31</guid>

					<description><![CDATA[<p>O Modbus é um protocolo de comunicação amplamente utilizado na indústria para conectar dispositivos eletrônicos, como sensores e atuadores. Com o suporte nativo no ESP32 por meio da biblioteca ESP-Modbus, integrá-lo a projetos embarcados torna-se uma tarefa eficiente e confiável. Este artigo explora como utilizar o ESP-Modbus na plataforma ESP-IDF, explicando conceitos-chave e orientando sobre [&#8230;]</p>
<p>The post <a href="https://mcu.tec.br/protoclos/introducao-ao-esp-modbus-com-esp-idf/">Introdução ao ESP-Modbus com ESP-IDF</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">O Modbus é um protocolo de comunicação amplamente utilizado na indústria para conectar dispositivos eletrônicos, como sensores e atuadores. Com o suporte nativo no ESP32 por meio da biblioteca ESP-Modbus, integrá-lo a projetos embarcados torna-se uma tarefa eficiente e confiável.</p>



<p class="wp-block-paragraph">Este artigo explora como utilizar o ESP-Modbus na plataforma ESP-IDF, explicando conceitos-chave e orientando sobre a configuração de comunicação com dispositivos Modbus em suas variantes mais comuns, como <strong>Modbus RTU</strong>, <strong>Modbus ASCII</strong> e <strong>Modbus TCP/IP</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Visão Geral do Modbus</h2>



<p class="wp-block-paragraph">O protocolo Modbus define regras de comunicação para troca de mensagens entre dispositivos mestre (master) e escravos (slaves) em uma rede. Ele é amplamente adotado em aplicações industriais devido à sua simplicidade e eficiência.</p>



<h3 class="wp-block-heading">Tipos de Modbus:</h3>



<ol class="wp-block-list">
<li><strong>Modbus RTU (Remote Terminal Unit):</strong>
<ul class="wp-block-list">
<li>Comunicação serial com dados representados em formato binário compacto.</li>



<li>Utiliza verificação de erros com checksum (CRC).</li>



<li>Requer intervalos de silêncio para enquadrar mensagens, sendo o <strong>RS-485</strong> a interface mais utilizada.</li>
</ul>
</li>



<li><strong>Modbus ASCII:</strong>
<ul class="wp-block-list">
<li>Dados em formato legível por humanos (ASCII).</li>



<li>Inclui checagem de erros com verificação longitudinal (LRC).</li>



<li>Mensagens são delimitadas por um caractere <code>:</code> no início e CR/LF no final.</li>
</ul>
</li>



<li><strong>Modbus TCP/IP:</strong>
<ul class="wp-block-list">
<li>Adaptação para redes Ethernet utilizando o protocolo TCP/IP.</li>



<li>Transmissão via porta padrão 502, sem necessidade de checksum adicional devido à proteção fornecida pelas camadas inferiores do TCP/IP.</li>
</ul>
</li>
</ol>



<p class="wp-block-paragraph">Os dados no Modbus são organizados em registros, que podem ser de quatro tipos principais:</p>



<ul class="wp-block-list">
<li><strong>Coils (Saídas discretas):</strong> Valores binários para controle de atuadores.</li>



<li><strong>Discrete Inputs (Entradas discretas):</strong> Leituras binárias de sensores.</li>



<li><strong>Holding Registers:</strong> Valores de 16 bits para leitura e escrita.</li>



<li><strong>Input Registers:</strong> Valores de 16 bits apenas para leitura.</li>
</ul>



<p class="wp-block-paragraph">A biblioteca ESP-Modbus do ESP32 é baseada na FreeModbus, oferecendo suporte para as implementações <strong>RTU</strong>, <strong>ASCII</strong> e <strong>TCP/IP</strong>, tanto para dispositivos mestre quanto escravo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Modelo de Mensagem e Mapeamento de Dados</h2>


<div class="wp-block-image">
<figure class="aligncenter"><img decoding="async" src="https://docs.espressif.com/projects/esp-idf/en/v4.4.3/esp32/_images/modbus-segment.png" alt="Modbus segment diagram"/><figcaption class="wp-element-caption">Modbus segment diagram</figcaption></figure>
</div>


<p class="wp-block-paragraph">O Modbus é um protocolo baseado em registros que define um modelo de comunicação estruturado, independente do meio físico utilizado para a transmissão de dados. Este modelo organiza as mensagens como transações entre dispositivos mestre e escravo, onde o mestre controla toda a comunicação.</p>



<h3 class="wp-block-heading">Comunicação Mestre-Escravo</h3>



<p class="wp-block-paragraph">Em uma rede Modbus:</p>



<ul class="wp-block-list">
<li>O <strong>mestre</strong> envia comandos para os dispositivos <strong>escravos</strong>.</li>



<li>Os <strong>escravos</strong> respondem aos comandos ou permanecem inativos se não forem endereçados.</li>



<li>Não há comunicação direta entre escravos.</li>
</ul>



<p class="wp-block-paragraph">No caso do <strong>Modbus TCP/IP</strong>, múltiplos mestres podem coexistir na mesma rede, aproveitando a natureza da comunicação IP.</p>



<h3 class="wp-block-heading">Tipos de Registros no Modbus<figure><img decoding="async" class="aligncenter" src="https://docs.espressif.com/projects/esp-idf/en/v4.4.3/esp32/_images/modbus-data-mapping.png" alt="Modbus data mapping"></figure></h3>



<p class="wp-block-paragraph">Os dispositivos mapeiam seus dados em quatro tipos de registros que representam características físicas, como leituras de sensores ou estados de atuadores. Abaixo, detalhamos esses tipos:</p>



<ol class="wp-block-list">
<li><strong>Coils (Saídas Discretas):</strong>
<ul class="wp-block-list">
<li>Bits de saída que podem ser controlados pelo mestre.</li>



<li>Geralmente usados para ligar/desligar dispositivos como relés.</li>
</ul>
</li>



<li><strong>Discrete Inputs (Entradas Discretas):</strong>
<ul class="wp-block-list">
<li>Bits de entrada somente leitura.</li>



<li>Utilizados para monitorar estados, como o fechamento de um contato.</li>
</ul>
</li>



<li><strong>Holding Registers:</strong>
<ul class="wp-block-list">
<li>Registros de 16 bits que permitem leitura e escrita.</li>



<li>Comumente usados para armazenar valores configuráveis, como setpoints de temperatura.</li>
</ul>
</li>



<li><strong>Input Registers:</strong>
<ul class="wp-block-list">
<li>Registros de 16 bits somente leitura.</li>



<li>Geralmente associados a sensores analógicos que enviam valores convertidos.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Mapeamento de Dados no ESP-Modbus</h3>



<p class="wp-block-paragraph">No ESP-Modbus, cada dispositivo na rede é identificado por um <strong>endereço escravo único</strong>, configurado em seu manual. O mestre deve conhecer o mapa de registros do dispositivo para acessar os dados corretamente. Esse mapa define:</p>



<ul class="wp-block-list">
<li>O tipo de registro (Coil, Holding, etc.).</li>



<li>O endereço inicial.</li>



<li>A quantidade de registros disponíveis.</li>
</ul>



<p class="wp-block-paragraph">Este mapeamento é essencial para configurar o Modbus no ESP32 e estabelecer uma comunicação eficiente entre dispositivos.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Inicialização da Porta Modbus</h2>



<p class="wp-block-paragraph">Para iniciar a comunicação Modbus em um ESP32 utilizando o ESP-Modbus, é necessário configurar corretamente a porta de comunicação. O ESP-Modbus suporta tanto comunicação <strong>serial</strong> (via RTU ou ASCII) quanto <strong>TCP/IP</strong>. A inicialização correta da porta é o primeiro passo para utilizar as APIs disponíveis.</p>



<h3 class="wp-block-heading">Configuração de Portas no ESP-Modbus</h3>



<p class="wp-block-paragraph">O ESP-Modbus fornece as seguintes funções para inicializar controladores Modbus, tanto para dispositivos mestre quanto escravo, dependendo do tipo de comunicação:</p>



<ul class="wp-block-list">
<li><p><strong>Serial (RTU/ASCII):</strong></p>
<ul class="wp-block-list">
<li><code>mbc_slave_init()</code>: Inicializa um escravo Modbus em comunicação serial.</li>



<li><code>mbc_master_init()</code>: Inicializa um mestre Modbus em comunicação serial.</li>
</ul>
</li>



<li><p><strong>TCP/IP:</strong></p>
<ul class="wp-block-list">
<li><code>mbc_slave_init_tcp()</code>: Inicializa um escravo Modbus em comunicação TCP/IP.</li>



<li><code>mbc_master_init_tcp()</code>: Inicializa um mestre Modbus em comunicação TCP/IP.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">A escolha da função depende do tipo de dispositivo (mestre ou escravo) e do meio de transmissão (serial ou TCP/IP).</p>



<h3 class="wp-block-heading">Exemplo de Inicialização</h3>



<p class="wp-block-paragraph">Para inicializar uma porta serial no modo escravo, o seguinte código pode ser usado:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="void* slave_handler = NULL;
// Estrutura de interface 
esp_err_t err = mbc_slave_init(MB_PORT_SERIAL_SLAVE, &amp;slave_handler); 
if (slave_handler == NULL || err != ESP_OK) {
  ESP_LOGE(TAG, &quot;Falha na inicialização do controlador Modbus.&quot;); 
}" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">slave_handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #616E88">// Estrutura de interface </span></span>
<span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_slave_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MB_PORT_SERIAL_SLAVE</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">slave_handler</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">slave_handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Falha na inicialização do controlador Modbus.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">No caso de comunicação TCP/IP, a inicialização segue um padrão similar, mas com a função mbc_slave_init_tcp:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="void* slave_handler = NULL;
esp_err_t err = mbc_slave_init_tcp(&amp;slave_handler);

if (slave_handler == NULL || err != ESP_OK) {
    ESP_LOGE(TAG, &quot;Falha na inicialização do controlador Modbus TCP.&quot;);
}" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">slave_handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_slave_init_tcp</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">slave_handler</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">slave_handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Falha na inicialização do controlador Modbus TCP.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Essas funções configuram a estrutura base para a comunicação Modbus e devem ser chamadas antes de qualquer outra operação relacionada ao protocolo.</p>



<h2 class="wp-block-heading">API Modbus Mestre &#8211; Visão Geral</h2>



<p class="wp-block-paragraph">A API do Modbus para dispositivos mestre no ESP32 oferece uma estrutura completa para configurar, acessar e gerenciar a comunicação com dispositivos escravos. Essa API segue uma sequência lógica de passos para configurar a comunicação e realizar transações.</p>



<h3 class="wp-block-heading">Etapas Principais da Comunicação Mestre</h3>



<ol class="wp-block-list">
<li><strong>Inicialização da Porta Modbus:</strong>
<ul class="wp-block-list">
<li>Configura a interface de comunicação (serial ou TCP/IP) e o controlador mestre.</li>
</ul>
</li>



<li><strong>Configuração do Acesso a Dados:</strong>
<ul class="wp-block-list">
<li>Define os parâmetros que o mestre acessará nos dispositivos escravos.</li>



<li>Utiliza um mapeamento chamado &#8220;Dicionário de Dados&#8221;, que associa identificadores únicos (CID) a registros Modbus.</li>
</ul>
</li>



<li><strong>Opções de Comunicação:</strong>
<ul class="wp-block-list">
<li>Configura parâmetros específicos, como baud rate (para serial) ou endereços IP (para TCP/IP).</li>
</ul>
</li>



<li><strong>Início da Comunicação:</strong>
<ul class="wp-block-list">
<li>Ativa o controlador Modbus, permitindo o envio e recebimento de dados entre mestre e escravos.</li>
</ul>
</li>



<li><strong>Finalização:</strong>
<ul class="wp-block-list">
<li>Libera recursos do controlador Modbus ao finalizar a comunicação.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Dicionário de Dados e CID</h3>



<p class="wp-block-paragraph">O ESP-Modbus introduz um nível de abstração acima do protocolo padrão, denominado &#8220;Dicionário de Dados&#8221;. Cada parâmetro acessível pelo mestre é identificado por:</p>



<ul class="wp-block-list">
<li><strong>CID (Identificador de Característica):</strong> Um número único que identifica um parâmetro no dispositivo escravo.</li>



<li><strong>Nome e Unidades:</strong> Uma descrição textual do parâmetro e sua unidade física (como °C para temperatura).</li>



<li><strong>Tipo de Registro e Endereço:</strong> Define o tipo de registro Modbus (Holding, Input, etc.) e seu endereço inicial no dispositivo escravo.</li>
</ul>



<p class="wp-block-paragraph">Exemplo de definição de parâmetros no Dicionário de Dados:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mb_parameter_descriptor_t device_parameters[] = {
    { CID_SER_NUM1, &quot;Serial_number_1&quot;, &quot;--&quot;, MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2, 0, PARAM_TYPE_U32, 4 },
    { CID_TEMP_DATA_1, &quot;Temperature_1&quot;, &quot;C&quot;, MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2, 0, PARAM_TYPE_FLOAT, 4 }
};
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">mb_parameter_descriptor_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">device_parameters</span><span style="color: #D8DEE9FF">[] </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">CID_SER_NUM1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Serial_number_1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">--</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_DEVICE_ADDR1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_INPUT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">PARAM_TYPE_U32</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">CID_TEMP_DATA_1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Temperature_1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">C</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_DEVICE_ADDR1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_HOLDING</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">PARAM_TYPE_FLOAT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Neste exemplo:</p>



<ul class="wp-block-list">
<li>O parâmetro <code>CID_SER_NUM1</code> refere-se ao número de série do dispositivo.</li>



<li>O parâmetro <code>CID_TEMP_DATA_1</code> mapeia um registro de temperatura em graus Celsius.</li>
</ul>



<h3 class="wp-block-heading">Configuração do Mestre</h3>



<p class="wp-block-paragraph">Após definir o Dicionário de Dados, ele deve ser associado ao controlador Modbus utilizando a função <code>mbc_master_set_descriptor()</code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="ESP_ERROR_CHECK(mbc_master_set_descriptor(&amp;device_parameters[0], num_device_parameters));
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_set_descriptor</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">device_parameters</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">]</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">num_device_parameters</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Isso permite que o mestre acesse os parâmetros do escravo conforme o mapeamento definido.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Configuração de Acesso a Dados no Mestre</h2>



<p class="wp-block-paragraph">Para que um dispositivo mestre possa acessar parâmetros de dispositivos escravos, é necessário configurar o acesso aos dados. Isso é realizado definindo os detalhes de cada parâmetro que será lido ou escrito, utilizando o <strong>Dicionário de Dados</strong> já apresentado.</p>



<h3 class="wp-block-heading">Estrutura do Dicionário de Dados</h3>



<p class="wp-block-paragraph">Cada entrada no Dicionário de Dados representa uma característica física ou lógica disponível no dispositivo escravo, como temperatura, pressão ou um número de série. A configuração inclui:</p>



<ul class="wp-block-list">
<li><strong>CID (Identificador de Característica):</strong> Um identificador único que referencia o parâmetro.</li>



<li><strong>Endereço do Registro:</strong> Define onde os dados estão localizados no mapa de registros do escravo.</li>



<li><strong>Tipo de Registro:</strong> Especifica se é um registro de entrada, holding, etc.</li>



<li><strong>Tamanho:</strong> Determina quantos registros Modbus são utilizados para armazenar o valor.</li>
</ul>



<h3 class="wp-block-heading">Exemplo Prático de Configuração</h3>



<p class="wp-block-paragraph">Abaixo está um exemplo de definição de parâmetros para dois dispositivos escravos conectados a um mestre:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mb_parameter_descriptor_t device_parameters[] = {
    { CID_TEMP_DATA_1, &quot;Temperature_1&quot;, &quot;C&quot;, MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2, 0, PARAM_TYPE_FLOAT, 4 },
    { CID_HUMIDITY_1, &quot;Humidity_1&quot;, &quot;%&quot;, MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 1, 0, PARAM_TYPE_U16, 2 },
    { CID_TEMP_DATA_2, &quot;Temperature_2&quot;, &quot;C&quot;, MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 0, 2, 0, PARAM_TYPE_FLOAT, 4 },
    { CID_HUMIDITY_2, &quot;Humidity_2&quot;, &quot;%&quot;, MB_DEVICE_ADDR2, MB_PARAM_INPUT, 2, 1, 0, PARAM_TYPE_U16, 2 }
};
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">mb_parameter_descriptor_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">device_parameters</span><span style="color: #D8DEE9FF">[] </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">CID_TEMP_DATA_1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Temperature_1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">C</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_DEVICE_ADDR1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_HOLDING</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">PARAM_TYPE_FLOAT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">CID_HUMIDITY_1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Humidity_1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">%</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_DEVICE_ADDR1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_INPUT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">PARAM_TYPE_U16</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">CID_TEMP_DATA_2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Temperature_2</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">C</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_DEVICE_ADDR2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_HOLDING</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">PARAM_TYPE_FLOAT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">CID_HUMIDITY_2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Humidity_2</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">%</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_DEVICE_ADDR2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_INPUT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">PARAM_TYPE_U16</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Neste exemplo:</p>



<ul class="wp-block-list">
<li><strong>CID_TEMP_DATA_1:</strong> Mapeia a temperatura do dispositivo 1 (endereço <code>MB_DEVICE_ADDR1</code>) em registros de holding.</li>



<li><strong>CID_HUMIDITY_1:</strong> Mapeia a umidade do dispositivo 1 como registro de entrada.</li>



<li><strong>CID_TEMP_DATA_2 e CID_HUMIDITY_2:</strong> Seguem a mesma lógica para o segundo dispositivo.</li>
</ul>



<p class="wp-block-paragraph">O número de parâmetros no Dicionário de Dados pode ser calculado automaticamente:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">num_device_parameters</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">device_parameters</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">device_parameters</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">]))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Configuração no Controlador Mestre</h3>



<p class="wp-block-paragraph">Após definir o Dicionário de Dados, ele deve ser registrado no controlador Modbus para permitir o acesso aos dispositivos escravos:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="ESP_ERROR_CHECK(mbc_master_set_descriptor(&amp;device_parameters[0], num_device_parameters));
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_set_descriptor</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">device_parameters</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">]</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">num_device_parameters</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Com essa configuração, o mestre está preparado para acessar os parâmetros definidos nos escravos, conforme as especificações do Dicionário de Dados.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Opções de Comunicação do Mestre</h2>



<p class="wp-block-paragraph">Depois de configurar os parâmetros de acesso no Dicionário de Dados, é necessário definir as opções de comunicação do mestre para garantir uma troca de dados eficiente e confiável com os dispositivos escravos. Essas opções incluem parâmetros de comunicação específicos para cada tipo de interface: serial ou TCP/IP.</p>



<h3 class="wp-block-heading">Configuração de Comunicação Serial</h3>



<p class="wp-block-paragraph">Ao utilizar a comunicação serial (Modbus RTU ou ASCII), os seguintes parâmetros devem ser definidos:</p>



<ul class="wp-block-list">
<li><strong>Porta Serial:</strong> Identifica qual porta UART será utilizada.</li>



<li><strong>Modo de Comunicação:</strong> Define se será RTU ou ASCII.</li>



<li><strong>Taxa de Baud:</strong> Determina a velocidade da transmissão em bits por segundo.</li>



<li><strong>Paridade:</strong> Especifica o tipo de verificação de paridade (nenhuma, ímpar ou par).</li>
</ul>



<p class="wp-block-paragraph">Exemplo de configuração para uma porta serial:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mb_communication_info_t comm_info = {
    .port = MB_PORT_NUM,        // Número da porta serial
    .mode = MB_MODE_RTU,        // Modo de comunicação Modbus (RTU ou ASCII)
    .baudrate = 9600,           // Taxa de transmissão em bits por segundo
    .parity = MB_PARITY_NONE    // Tipo de paridade (nenhuma neste caso)
};

// Configura o mestre Modbus com os parâmetros de comunicação
ESP_ERROR_CHECK(mbc_master_setup((void*)&amp;comm_info));
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">mb_communication_info_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">port</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PORT_NUM</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">// Número da porta serial</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">mode</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_MODE_RTU</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">// Modo de comunicação Modbus (RTU ou ASCII)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">baudrate</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">9600</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">           </span><span style="color: #616E88">// Taxa de transmissão em bits por segundo</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">parity</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARITY_NONE</span><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">// Tipo de paridade (nenhuma neste caso)</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Configura o mestre Modbus com os parâmetros de comunicação</span></span>
<span class="line"><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_setup</span><span style="color: #D8DEE9FF">((</span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Configuração de Comunicação TCP/IP</h3>



<p class="wp-block-paragraph">Para comunicação via TCP/IP, além dos parâmetros gerais, é necessário configurar os endereços IP dos dispositivos escravos. Esses endereços são utilizados para identificar cada dispositivo na rede.</p>



<p class="wp-block-paragraph">Exemplo de configuração para uma rede TCP/IP:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="char* slave_ip_address_table[MB_SLAVE_COUNT] = {
    &quot;192.168.1.2&quot;, // Endereço IP do escravo 1
    &quot;192.168.1.3&quot;, // Endereço IP do escravo 2
    NULL           // Término da tabela
};

mb_communication_info_t comm_info = {
    .ip_port = MB_TCP_PORT,                    // Porta Modbus TCP (padrão 502)
    .ip_addr_type = MB_IPV4,                   // Tipo de endereço IP (IPv4)
    .ip_mode = MB_MODE_TCP,                    // Modo de comunicação TCP
    .ip_addr = (void*)slave_ip_address_table,  // Tabela de endereços IP dos escravos
    .ip_netif_ptr = esp_netif_ptr              // Ponteiro para a interface de rede
};

// Configura o mestre Modbus com os parâmetros de comunicação
ESP_ERROR_CHECK(mbc_master_setup((void*)&amp;comm_info));
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">char</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">slave_ip_address_table</span><span style="color: #D8DEE9FF">[</span><span style="color: #D8DEE9">MB_SLAVE_COUNT</span><span style="color: #D8DEE9FF">] </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">192.168.1.2</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Endereço IP do escravo 1</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">192.168.1.3</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Endereço IP do escravo 2</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">           </span><span style="color: #616E88">// Término da tabela</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">mb_communication_info_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_port</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_TCP_PORT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">                    </span><span style="color: #616E88">// Porta Modbus TCP (padrão 502)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_addr_type</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_IPV4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">                   </span><span style="color: #616E88">// Tipo de endereço IP (IPv4)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_mode</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_MODE_TCP</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">                    </span><span style="color: #616E88">// Modo de comunicação TCP</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_addr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">slave_ip_address_table</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// Tabela de endereços IP dos escravos</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_netif_ptr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">esp_netif_ptr</span><span style="color: #D8DEE9FF">              </span><span style="color: #616E88">// Ponteiro para a interface de rede</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Configura o mestre Modbus com os parâmetros de comunicação</span></span>
<span class="line"><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_setup</span><span style="color: #D8DEE9FF">((</span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Considerações Importantes</h3>



<ol class="wp-block-list">
<li>Para comunicação <strong>RS-485</strong>, é necessário configurar o modo UART e os pinos apropriados usando as APIs UART do ESP-IDF.</li>



<li>No caso de redes TCP/IP, a descoberta automática de dispositivos pode ser configurada utilizando o serviço mDNS.</li>
</ol>



<p class="wp-block-paragraph">Com as opções de comunicação configuradas, o mestre está pronto para iniciar a troca de dados com os escravos.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Comunicação do Mestre</h2>



<p class="wp-block-paragraph">Após configurar o mestre Modbus e suas opções de comunicação, o próximo passo é iniciar a comunicação com os dispositivos escravos. O ESP-Modbus oferece APIs para iniciar, enviar requisições e processar as respostas recebidas.</p>



<h3 class="wp-block-heading">Inicialização da Comunicação</h3>



<p class="wp-block-paragraph">A comunicação do mestre Modbus é iniciada com a chamada da função <code>mbc_master_start()</code>, que ativa a pilha Modbus e permite a troca de dados.</p>



<p class="wp-block-paragraph">Exemplo de inicialização:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="esp_err_t err = mbc_master_start();
if (err != ESP_OK) {
    ESP_LOGE(TAG, &quot;Falha ao iniciar o controlador Modbus, erro = %x.&quot;, err);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_master_start</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Falha ao iniciar o controlador Modbus, erro = %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Envio de Requisições</h3>



<p class="wp-block-paragraph">O mestre envia requisições aos escravos utilizando a função <code>mbc_master_send_request()</code>. Essa função é bloqueante, ou seja, ela aguarda uma resposta do escravo antes de continuar.</p>



<p class="wp-block-paragraph">Exemplo básico de envio de requisição:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mb_param_request_t request = {
    .slave_addr = 1,          // Endereço do dispositivo escravo
    .command = MB_FUNC_READ,  // Comando Modbus (ex.: leitura de registros)
    .reg_start = 0,           // Endereço inicial do registro
    .reg_size = 2             // Número de registros a serem lidos
};

uint8_t response_data[4]; // Buffer para armazenar a resposta
esp_err_t err = mbc_master_send_request(&amp;request, response_data);
if (err == ESP_OK) {
    ESP_LOGI(TAG, &quot;Requisição bem-sucedida. Dados recebidos.&quot;);
} else {
    ESP_LOGE(TAG, &quot;Erro na requisição Modbus, código de erro: %x.&quot;, err);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">mb_param_request_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">request</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">slave_addr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">          </span><span style="color: #616E88">// Endereço do dispositivo escravo</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">command</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_FUNC_READ</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// Comando Modbus (ex.: leitura de registros)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">reg_start</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">           </span><span style="color: #616E88">// Endereço inicial do registro</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">reg_size</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF">             </span><span style="color: #616E88">// Número de registros a serem lidos</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">response_data</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">]</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Buffer para armazenar a resposta</span></span>
<span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_master_send_request</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">request</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">response_data</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Requisição bem-sucedida. Dados recebidos.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro na requisição Modbus, código de erro: %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Leitura de Dados</h3>



<p class="wp-block-paragraph">O mestre pode acessar os valores de parâmetros definidos no Dicionário de Dados utilizando <code>mbc_master_get_parameter()</code>. Essa função permite recuperar os dados mapeados por um CID específico.</p>



<p class="wp-block-paragraph">Exemplo de leitura de parâmetro:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const mb_parameter_descriptor_t* param_descriptor = NULL;
uint8_t data_buffer[4]; // Buffer para armazenar os dados
uint8_t data_type;

esp_err_t err = mbc_master_get_cid_info(CID_TEMP_DATA_1, &amp;param_descriptor);
if (err == ESP_OK) {
    err = mbc_master_get_parameter(param_descriptor-&gt;cid, (char*)param_descriptor-&gt;param_key, data_buffer, &amp;data_type);
    if (err == ESP_OK) {
        ESP_LOGI(TAG, &quot;Parâmetro: %s, Valor: 0x%08x&quot;, param_descriptor-&gt;param_key, *(uint32_t*)data_buffer);
    } else {
        ESP_LOGE(TAG, &quot;Erro ao ler o parâmetro, código de erro: %x.&quot;, err);
    }
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mb_parameter_descriptor_t</span><span style="color: #D8DEE9FF">* param_descriptor </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data_buffer</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">]</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Buffer para armazenar os dados</span></span>
<span class="line"><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data_type</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_master_get_cid_info</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">CID_TEMP_DATA_1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> ¶</span><span style="color: #D8DEE9">m_descriptor</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_master_get_parameter</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">param_descriptor</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">cid</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">char</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">param_descriptor</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">param_key</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data_buffer</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">data_type</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Parâmetro: %s, Valor: 0x%08x</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">param_descriptor</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">param_key</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint32_t</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">data_buffer</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro ao ler o parâmetro, código de erro: %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Escrita de Dados</h3>



<p class="wp-block-paragraph">O mestre também pode alterar valores nos registros de um escravo utilizando <code>mbc_master_set_parameter()</code>.</p>



<p class="wp-block-paragraph">Exemplo de escrita:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="uint8_t new_value[4] = {0x12, 0x34, 0x56, 0x78};
esp_err_t err = mbc_master_set_parameter(CID_TEMP_DATA_1, &quot;Temperature_1&quot;, new_value, NULL);
if (err == ESP_OK) {
    ESP_LOGI(TAG, &quot;Parâmetro atualizado com sucesso.&quot;);
} else {
    ESP_LOGE(TAG, &quot;Erro ao atualizar parâmetro, código de erro: %x.&quot;, err);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">new_value</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">] </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">0x12</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x34</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x56</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x78</span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_master_set_parameter</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">CID_TEMP_DATA_1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Temperature_1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">new_value</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Parâmetro atualizado com sucesso.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro ao atualizar parâmetro, código de erro: %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Encerramento do Mestre Modbus</h2>



<p class="wp-block-paragraph">Ao finalizar a utilização do mestre Modbus, é essencial encerrar corretamente a pilha de comunicação para liberar os recursos do sistema. O ESP-Modbus oferece APIs específicas para garantir que todo o contexto do controlador seja destruído de forma segura.</p>



<h3 class="wp-block-heading">Parada da Pilha Modbus</h3>



<p class="wp-block-paragraph">A função <code>mbc_master_stop()</code> deve ser chamada para interromper a pilha de comunicação. Isso encerra todas as operações ativas e desativa o controlador.</p>



<p class="wp-block-paragraph">Exemplo de parada da pilha:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="esp_err_t err = mbc_master_stop();
if (err == ESP_OK) {
    ESP_LOGI(TAG, &quot;Pilha Modbus parada com sucesso.&quot;);
} else {
    ESP_LOGE(TAG, &quot;Erro ao parar a pilha Modbus, código de erro: %x.&quot;, err);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_master_stop</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Pilha Modbus parada com sucesso.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro ao parar a pilha Modbus, código de erro: %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Destruição do Controlador</h3>



<p class="wp-block-paragraph">Após a parada da pilha, o controlador Modbus deve ser destruído utilizando a função <code>mbc_master_destroy()</code>. Isso libera a memória e outros recursos alocados durante a inicialização.</p>



<p class="wp-block-paragraph">Exemplo de destruição do controlador:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="esp_err_t err = mbc_master_destroy();
if (err == ESP_OK) {
    ESP_LOGI(TAG, &quot;Controlador Modbus destruído com sucesso.&quot;);
} else {
    ESP_LOGE(TAG, &quot;Erro ao destruir o controlador Modbus, código de erro: %x.&quot;, err);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_master_destroy</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Controlador Modbus destruído com sucesso.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro ao destruir o controlador Modbus, código de erro: %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Boas Práticas</h3>



<ul class="wp-block-list">
<li><strong>Verificação de Erros:</strong> Sempre verifique os códigos de retorno das funções para identificar possíveis falhas e tratar erros de forma adequada.</li>



<li><strong>Liberação de Recursos:</strong> Certifique-se de que a função <code>mbc_master_destroy()</code> seja chamada antes de finalizar a aplicação para evitar vazamentos de memória.</li>



<li><strong>Sincronização:</strong> Garanta que todas as operações Modbus tenham sido concluídas antes de encerrar a pilha.</li>
</ul>



<p class="wp-block-paragraph">Com esses passos, o ciclo de vida do controlador mestre Modbus é finalizado de forma segura e eficiente.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">API Modbus Escravo &#8211; Visão Geral</h2>



<p class="wp-block-paragraph">A API Modbus para dispositivos escravos no ESP32 permite configurar e gerenciar a comunicação com mestres Modbus. Assim como a API para mestres, a API para escravos segue uma sequência lógica de configuração e operação.</p>



<h3 class="wp-block-heading">Etapas Principais da Comunicação Escravo</h3>



<ol class="wp-block-list">
<li><strong>Inicialização da Porta Modbus:</strong>
<ul class="wp-block-list">
<li>Configura a interface de comunicação (serial ou TCP/IP) e o controlador escravo.</li>
</ul>
</li>



<li><strong>Configuração de Acesso a Dados:</strong>
<ul class="wp-block-list">
<li>Define os registros que estarão disponíveis para acesso pelo mestre, como holding registers ou input registers.</li>
</ul>
</li>



<li><strong>Opções de Comunicação:</strong>
<ul class="wp-block-list">
<li>Configura parâmetros específicos, como taxa de transmissão e endereços de comunicação.</li>
</ul>
</li>



<li><strong>Início da Comunicação:</strong>
<ul class="wp-block-list">
<li>Ativa a pilha Modbus, permitindo a troca de dados entre o escravo e o mestre.</li>
</ul>
</li>



<li><strong>Finalização:</strong>
<ul class="wp-block-list">
<li>Libera os recursos do controlador ao finalizar a comunicação.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Estrutura de Dados no Escravo</h3>



<p class="wp-block-paragraph">Assim como no mestre, o escravo utiliza estruturas de dados para organizar os registros Modbus acessíveis pelo mestre. A configuração de cada área de registro inclui:</p>



<ul class="wp-block-list">
<li><strong>Tipo de Registro:</strong> Define se é um holding register, input register, coil, ou discrete input.</li>



<li><strong>Endereço Inicial:</strong> Especifica a posição inicial do registro na memória do dispositivo.</li>



<li><strong>Tamanho:</strong> Determina o número de registros disponíveis para acesso.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Configuração de Acesso a Dados no Escravo</h2>



<p class="wp-block-paragraph">A configuração de acesso a dados no escravo Modbus é uma etapa essencial para disponibilizar registros aos mestres. No ESP-Modbus, isso é feito definindo áreas de memória específicas que armazenarão os dados acessíveis. Essas áreas são mapeadas para tipos de registros Modbus, como <strong>Holding Registers</strong> e <strong>Input Registers</strong>.</p>



<h3 class="wp-block-heading">Definindo Áreas de Registro</h3>



<p class="wp-block-paragraph">Cada tipo de registro Modbus no escravo é configurado utilizando a estrutura <code>mb_register_area_descriptor_t</code>. Essa estrutura especifica:</p>



<ul class="wp-block-list">
<li><strong>Offset Inicial:</strong> A posição relativa do registro dentro do tipo configurado.</li>



<li><strong>Tipo de Registro:</strong> Indica se a área é de Holding Registers, Input Registers, Coils ou Discrete Inputs.</li>



<li><strong>Endereço de Memória:</strong> Um ponteiro para a área de memória onde os dados serão armazenados.</li>



<li><strong>Tamanho da Área:</strong> Define o número de registros disponíveis para leitura/escrita.</li>
</ul>



<p class="wp-block-paragraph">Exemplo de configuração de áreas de registro:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="#define MB_REG_INPUT_START_AREA0    (0)
#define MB_REG_HOLDING_START_AREA0  (0)
#define MB_REG_HOLD_CNT             (100) // Número de registros de holding
#define MB_REG_INPUT_CNT            (100) // Número de registros de input

mb_register_area_descriptor_t reg_area; // Estrutura de descrição da área de registros

// Área de registros de holding
uint16_t holding_reg_area[MB_REG_HOLD_CNT] = {0};
reg_area.type = MB_PARAM_HOLDING;
reg_area.start_offset = MB_REG_HOLDING_START_AREA0;
reg_area.address = (void*)&amp;holding_reg_area[0];
reg_area.size = sizeof(holding_reg_area);
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));

// Área de registros de input
uint16_t input_reg_area[MB_REG_INPUT_CNT] = {0};
reg_area.type = MB_PARAM_INPUT;
reg_area.start_offset = MB_REG_INPUT_START_AREA0;
reg_area.address = (void*)&amp;input_reg_area[0];
reg_area.size = sizeof(input_reg_area);
ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">MB_REG_INPUT_START_AREA0</span><span style="color: #D8DEE9FF">    (</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">MB_REG_HOLDING_START_AREA0</span><span style="color: #D8DEE9FF">  (</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">MB_REG_HOLD_CNT</span><span style="color: #D8DEE9FF">             (</span><span style="color: #B48EAD">100</span><span style="color: #D8DEE9FF">) </span><span style="color: #616E88">// Número de registros de holding</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">MB_REG_INPUT_CNT</span><span style="color: #D8DEE9FF">            (</span><span style="color: #B48EAD">100</span><span style="color: #D8DEE9FF">) </span><span style="color: #616E88">// Número de registros de input</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">mb_register_area_descriptor_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">reg_area</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Estrutura de descrição da área de registros</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Área de registros de holding</span></span>
<span class="line"><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">holding_reg_area</span><span style="color: #D8DEE9FF">[</span><span style="color: #D8DEE9">MB_REG_HOLD_CNT</span><span style="color: #D8DEE9FF">] </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">reg_area</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_HOLDING</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">reg_area</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">start_offset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_REG_HOLDING_START_AREA0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">reg_area</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">address</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">holding_reg_area</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">]</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">reg_area</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">size</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">holding_reg_area</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_slave_set_descriptor</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">reg_area</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Área de registros de input</span></span>
<span class="line"><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">input_reg_area</span><span style="color: #D8DEE9FF">[</span><span style="color: #D8DEE9">MB_REG_INPUT_CNT</span><span style="color: #D8DEE9FF">] </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">reg_area</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_INPUT</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">reg_area</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">start_offset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_REG_INPUT_START_AREA0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">reg_area</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">address</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">input_reg_area</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">]</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">reg_area</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">size</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">input_reg_area</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_slave_set_descriptor</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">reg_area</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Proteção e Acesso aos Registros</h3>



<p class="wp-block-paragraph">Para evitar inconsistências durante a escrita/leitura dos registros, é importante proteger as áreas de memória com seções críticas. Exemplo:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="portENTER_CRITICAL(&amp;param_lock);
holding_reg_area[2] += 10; // Atualizando um registro
portEXIT_CRITICAL(&amp;param_lock);
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">portENTER_CRITICAL</span><span style="color: #D8DEE9FF">(¶</span><span style="color: #D8DEE9">m_lock</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">holding_reg_area</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF">] </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">10</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Atualizando um registro</span></span>
<span class="line"><span style="color: #88C0D0">portEXIT_CRITICAL</span><span style="color: #D8DEE9FF">(¶</span><span style="color: #D8DEE9">m_lock</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Requisitos para a Configuração</h3>



<ul class="wp-block-list">
<li>Pelo menos uma área de cada tipo de registro necessário deve ser configurada.</li>



<li>Caso um mestre tente acessar uma área não configurada, será gerada uma exceção Modbus.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Opções de Comunicação do Escravo</h2>



<p class="wp-block-paragraph">Após configurar as áreas de registro, é necessário definir as opções de comunicação para o escravo Modbus. Esses parâmetros garantem que o dispositivo esteja corretamente configurado para se comunicar com o mestre, seja em modo serial (RTU/ASCII) ou TCP/IP.</p>



<h3 class="wp-block-heading">Configuração de Comunicação Serial</h3>



<p class="wp-block-paragraph">Na comunicação serial, os parâmetros principais são:</p>



<ul class="wp-block-list">
<li><strong>Porta UART:</strong> Define qual porta física será utilizada.</li>



<li><strong>Modo de Comunicação:</strong> Indica se será RTU ou ASCII.</li>



<li><strong>Endereço do Escravo:</strong> Identifica unicamente o dispositivo na rede.</li>



<li><strong>Taxa de Baud:</strong> Determina a velocidade de transmissão.</li>



<li><strong>Paridade:</strong> Configura o tipo de paridade (nenhuma, ímpar ou par).</li>
</ul>



<p class="wp-block-paragraph">Exemplo de configuração serial:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="#define MB_SLAVE_DEV_SPEED 9600
#define MB_SLAVE_ADDR 1
#define MB_SLAVE_PORT_NUM 2

mb_communication_info_t comm_info = {
    .mode = MB_MODE_RTU,                    // Modo RTU
    .slave_addr = MB_SLAVE_ADDR,            // Endereço do escravo
    .port = MB_SLAVE_PORT_NUM,              // Porta UART
    .baudrate = MB_SLAVE_DEV_SPEED,         // Taxa de baud
    .parity = MB_PARITY_NONE                // Sem paridade
};

// Configura o escravo Modbus com os parâmetros definidos
ESP_ERROR_CHECK(mbc_slave_setup((void*)&amp;comm_info));
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_SLAVE_DEV_SPEED</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">9600</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_SLAVE_ADDR</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_SLAVE_PORT_NUM</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">mb_communication_info_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">mode</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_MODE_RTU</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">                    </span><span style="color: #616E88">// Modo RTU</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">slave_addr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_SLAVE_ADDR</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">// Endereço do escravo</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">port</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_SLAVE_PORT_NUM</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">              </span><span style="color: #616E88">// Porta UART</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">baudrate</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_SLAVE_DEV_SPEED</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">         </span><span style="color: #616E88">// Taxa de baud</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">parity</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARITY_NONE</span><span style="color: #D8DEE9FF">                </span><span style="color: #616E88">// Sem paridade</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Configura o escravo Modbus com os parâmetros definidos</span></span>
<span class="line"><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_slave_setup</span><span style="color: #D8DEE9FF">((</span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Configuração de Comunicação TCP/IP</h3>



<p class="wp-block-paragraph">Na comunicação via TCP/IP, o escravo precisa estar associado a uma interface de rede válida e configurado para escutar em uma porta específica. A porta padrão para Modbus TCP é a <strong>502</strong>.</p>



<p class="wp-block-paragraph">Exemplo de configuração TCP/IP:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mb_communication_info_t comm_info = {
    .ip_port = MB_TCP_PORT,                    // Porta Modbus TCP (padrão 502)
    .ip_addr_type = MB_IPV4,                   // IPv4
    .ip_mode = MB_MODE_TCP,                    // Modo TCP
    .ip_addr = NULL,                           // Aceita conexões de qualquer cliente
    .ip_netif_ptr = esp_netif_ptr              // Ponteiro para a interface de rede
};

// Configura o escravo Modbus para comunicação TCP/IP
ESP_ERROR_CHECK(mbc_slave_setup((void*)&amp;comm_info));
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">mb_communication_info_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_port</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_TCP_PORT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">                    </span><span style="color: #616E88">// Porta Modbus TCP (padrão 502)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_addr_type</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_IPV4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">                   </span><span style="color: #616E88">// IPv4</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_mode</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_MODE_TCP</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">                    </span><span style="color: #616E88">// Modo TCP</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_addr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">                           </span><span style="color: #616E88">// Aceita conexões de qualquer cliente</span></span>
<span class="line"><span style="color: #D8DEE9FF">    .</span><span style="color: #D8DEE9">ip_netif_ptr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">esp_netif_ptr</span><span style="color: #D8DEE9FF">              </span><span style="color: #616E88">// Ponteiro para a interface de rede</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Configura o escravo Modbus para comunicação TCP/IP</span></span>
<span class="line"><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_slave_setup</span><span style="color: #D8DEE9FF">((</span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Considerações para Comunicação Estável</h3>



<ol class="wp-block-list">
<li><strong>RS-485:</strong> Caso a interface serial utilize RS-485, configure os pinos UART e o modo half-duplex utilizando as APIs UART do ESP-IDF.</li>



<li><strong>Descoberta Automática:</strong> Para TCP/IP, é possível usar o serviço mDNS para facilitar a descoberta de dispositivos na rede.</li>



<li><strong>Respostas em Tempo Real:</strong> Certifique-se de que os registros necessários estejam configurados para evitar erros de timeout no mestre.</li>
</ol>



<p class="wp-block-paragraph">Com os parâmetros de comunicação configurados, o escravo está pronto para se comunicar com o mestre.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Comunicação do Escravo</h2>



<p class="wp-block-paragraph">Com as áreas de registro e as opções de comunicação configuradas, o escravo Modbus está pronto para iniciar a troca de dados com o mestre. O ESP-Modbus oferece APIs para gerenciar eventos e processar acessos aos registros configurados.</p>



<h3 class="wp-block-heading">Início da Comunicação</h3>



<p class="wp-block-paragraph">A comunicação do escravo é iniciada com a função <code>mbc_slave_start()</code>. Isso ativa a pilha Modbus, permitindo que o dispositivo receba e responda às requisições do mestre.</p>



<p class="wp-block-paragraph">Exemplo de inicialização:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="esp_err_t err = mbc_slave_start();
if (err == ESP_OK) {
    ESP_LOGI(TAG, &quot;Escravo Modbus iniciado com sucesso.&quot;);
} else {
    ESP_LOGE(TAG, &quot;Erro ao iniciar o escravo Modbus, código: %x.&quot;, err);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_slave_start</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Escravo Modbus iniciado com sucesso.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro ao iniciar o escravo Modbus, código: %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Monitoramento de Eventos</h3>



<p class="wp-block-paragraph">O escravo pode monitorar eventos relacionados ao acesso aos registros utilizando a função <code>mbc_slave_check_event()</code>. Essa função é bloqueante e retorna o tipo de evento ocorrido, como leitura ou escrita em um registro.</p>



<p class="wp-block-paragraph">Exemplo de monitoramento de eventos:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="#define MB_READ_MASK (MB_EVENT_INPUT_REG_RD | MB_EVENT_HOLDING_REG_RD)
#define MB_WRITE_MASK (MB_EVENT_HOLDING_REG_WR)
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)

mb_event_group_t event = mbc_slave_check_event(MB_READ_WRITE_MASK);

if (event &amp; MB_EVENT_HOLDING_REG_WR) {
    ESP_LOGI(TAG, &quot;Escrita em Holding Register detectada.&quot;);
} else if (event &amp; MB_EVENT_INPUT_REG_RD) {
    ESP_LOGI(TAG, &quot;Leitura em Input Register detectada.&quot;);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">MB_READ_MASK</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">MB_EVENT_INPUT_REG_RD</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_EVENT_HOLDING_REG_RD</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">MB_WRITE_MASK</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">MB_EVENT_HOLDING_REG_WR</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">MB_READ_WRITE_MASK</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">MB_READ_MASK</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_WRITE_MASK</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">mb_event_group_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">event</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_slave_check_event</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MB_READ_WRITE_MASK</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">event</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_EVENT_HOLDING_REG_WR</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Escrita em Holding Register detectada.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">event</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_EVENT_INPUT_REG_RD</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Leitura em Input Register detectada.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Acesso a Parâmetros</h3>



<p class="wp-block-paragraph">A função <code>mbc_slave_get_param_info()</code> permite obter detalhes sobre o registro acessado pelo mestre, como tipo de registro, endereço e tamanho.</p>



<p class="wp-block-paragraph">Exemplo de acesso:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="mb_param_info_t reg_info;
esp_err_t err = mbc_slave_get_param_info(&amp;reg_info, MB_PAR_INFO_GET_TOUT);
if (err == ESP_OK) {
    ESP_LOGI(TAG, &quot;Registro acessado: Tipo=%u, Endereço=%u, Tamanho=%u&quot;,
             reg_info.type, reg_info.mb_offset, reg_info.size);
} else {
    ESP_LOGE(TAG, &quot;Erro ao obter informações do parâmetro, código: %x.&quot;, err);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">mb_param_info_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">reg_info</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_slave_get_param_info</span><span style="color: #D8DEE9FF">(®</span><span style="color: #D8DEE9">_info</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PAR_INFO_GET_TOUT</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Registro acessado: Tipo=%u, Endereço=%u, Tamanho=%u</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">             </span><span style="color: #D8DEE9">reg_info</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">type</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">reg_info</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">mb_offset</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">reg_info</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">size</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro ao obter informações do parâmetro, código: %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Respostas em Tempo Real</h3>



<p class="wp-block-paragraph">O escravo responde automaticamente às requisições do mestre com base nos registros configurados. Certifique-se de que as áreas de registro estejam atualizadas com os valores corretos para evitar comportamentos inesperados.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Encerramento do Escravo Modbus</h2>



<p class="wp-block-paragraph">Ao finalizar a operação do escravo Modbus, é fundamental encerrar corretamente a pilha de comunicação e liberar os recursos alocados. Isso garante a estabilidade do sistema e evita vazamentos de memória.</p>



<h3 class="wp-block-heading">Parada da Pilha Modbus</h3>



<p class="wp-block-paragraph">A função <code>mbc_slave_stop()</code> é usada para interromper a pilha Modbus. Essa chamada encerra todas as operações ativas do escravo.</p>



<p class="wp-block-paragraph">Exemplo de parada:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="esp_err_t err = mbc_slave_stop();
if (err == ESP_OK) {
    ESP_LOGI(TAG, &quot;Pilha Modbus do escravo parada com sucesso.&quot;);
} else {
    ESP_LOGE(TAG, &quot;Erro ao parar a pilha Modbus, código: %x.&quot;, err);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_slave_stop</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Pilha Modbus do escravo parada com sucesso.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro ao parar a pilha Modbus, código: %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Destruição do Controlador</h3>



<p class="wp-block-paragraph">Após parar a pilha, a função <code>mbc_slave_destroy()</code> deve ser chamada para destruir o controlador Modbus e liberar todos os recursos alocados durante a inicialização.</p>



<p class="wp-block-paragraph">Exemplo de destruição:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="esp_err_t err = mbc_slave_destroy();
if (err == ESP_OK) {
    ESP_LOGI(TAG, &quot;Controlador do escravo Modbus destruído com sucesso.&quot;);
} else {
    ESP_LOGE(TAG, &quot;Erro ao destruir o controlador Modbus, código: %x.&quot;, err);
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">esp_err_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_slave_destroy</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ESP_OK</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Controlador do escravo Modbus destruído com sucesso.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGE</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Erro ao destruir o controlador Modbus, código: %x.</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">err</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Boas Práticas</h3>



<ol class="wp-block-list">
<li><strong>Verificação de Operações Ativas:</strong> Antes de encerrar a pilha, certifique-se de que todas as operações de leitura/escrita tenham sido concluídas.</li>



<li><strong>Liberação de Recursos:</strong> Sempre chame <code>mbc_slave_destroy()</code> para evitar vazamentos de memória ou instabilidades.</li>



<li><strong>Sincronização de Tarefas:</strong> Caso múltiplas tarefas acessem os registros Modbus, garanta que todas tenham finalizado antes de destruir o controlador.</li>
</ol>



<p class="wp-block-paragraph">Com esses passos, o ciclo de vida do escravo Modbus é encerrado de forma segura e eficiente.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Possíveis Problemas de Comunicação e Soluções</h2>



<p class="wp-block-paragraph">Durante a implementação do protocolo Modbus, podem ocorrer problemas de comunicação entre o mestre e os escravos. A identificação e a solução desses problemas são essenciais para garantir o funcionamento correto do sistema.</p>



<h3 class="wp-block-heading">Principais Erros e Soluções</h3>



<ol class="wp-block-list">
<li><strong>Requisição Inválida (ESP_ERR_NOT_SUPPORTED &#8211; Código: 0x106)</strong>
<ul class="wp-block-list">
<li><strong>Causa:</strong> O mestre enviou uma requisição para um registro ou comando não suportado pelo escravo.</li>



<li><strong>Solução:</strong> Verifique o mapa de registros do escravo e ajuste a requisição do mestre para corresponder às capacidades do dispositivo.</li>
</ul>
</li>



<li><strong>Timeout na Resposta do Escravo (ESP_ERR_TIMEOUT &#8211; Código: 0x107)</strong>
<ul class="wp-block-list">
<li><strong>Causa:</strong> O escravo não respondeu dentro do tempo esperado.</li>



<li><strong>Solução:</strong> Certifique-se de que:
<ul class="wp-block-list">
<li>O escravo está conectado corretamente.</li>



<li>A taxa de baud e os parâmetros de comunicação (como paridade) são compatíveis entre mestre e escravo.</li>



<li>O endereço do escravo na requisição está correto.</li>
</ul>
</li>
</ul>
</li>



<li><strong>Resposta Inválida (ESP_ERR_INVALID_RESPONSE &#8211; Código: 0x108)</strong>
<ul class="wp-block-list">
<li><strong>Causa:</strong> O mestre recebeu uma resposta corrompida ou com erro de validação (checksum inválido).</li>



<li><strong>Solução:</strong> Verifique a integridade do cabo de comunicação (no caso de RTU/ASCII) ou a estabilidade da conexão de rede (no caso de TCP/IP). Além disso, confirme que os parâmetros Modbus no escravo estão configurados corretamente.</li>
</ul>
</li>



<li><strong>Estado Inválido (ESP_ERR_INVALID_STATE &#8211; Código: 0x103)</strong>
<ul class="wp-block-list">
<li><strong>Causa:</strong> Erro crítico no controlador Modbus, como sequência de comandos incorreta ou controlador ocupado.</li>



<li><strong>Solução:</strong> Reinicie o controlador Modbus no mestre ou no escravo. Verifique se múltiplas tarefas estão acessando o controlador simultaneamente e sincronize-as.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Dicas para Diagnóstico</h3>



<ul class="wp-block-list">
<li><strong>Logs Detalhados:</strong> Ative logs no ESP-IDF para capturar mensagens de erro detalhadas, como falhas de inicialização ou problemas durante a execução.</li>



<li><strong>Testes Isolados:</strong> Teste cada dispositivo escravo individualmente antes de integrar vários dispositivos na rede.</li>



<li><strong>Osciloscópio ou Analisador de Rede:</strong> Use ferramentas de diagnóstico para verificar os sinais na linha de comunicação serial ou monitorar pacotes TCP/IP.</li>
</ul>



<h3 class="wp-block-heading">Exemplos de Mensagens de Erro</h3>



<p class="wp-block-paragraph">Um exemplo de mensagem de erro capturada nos logs do mestre:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="E (1692332) MB_CONTROLLER_MASTER: mbc_master_get_parameter(111): SERIAL master get parameter failure error=(0x107) (ESP_ERR_TIMEOUT).
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #88C0D0">E</span><span style="color: #D8DEE9FF"> (</span><span style="color: #B48EAD">1692332</span><span style="color: #D8DEE9FF">) MB_CONTROLLER_MASTER</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mbc_master_get_parameter</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">111</span><span style="color: #D8DEE9FF">): </span><span style="color: #D8DEE9">SERIAL</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">master</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">get</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">parameter</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">failure</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">error</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0x107</span><span style="color: #D8DEE9FF">) (</span><span style="color: #D8DEE9">ESP_ERR_TIMEOUT</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">.</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Neste caso, o erro indica que o escravo não respondeu no tempo esperado. A solução seria revisar as conexões físicas e os parâmetros de comunicação.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Exemplos de Aplicação</h2>



<p class="wp-block-paragraph">O ESP-Modbus fornece suporte completo para implementar soluções Modbus em dispositivos ESP32, permitindo a integração com uma ampla variedade de dispositivos industriais. Abaixo estão exemplos práticos de aplicações para mestre e escravo, baseados nas APIs discutidas.</p>



<h3 class="wp-block-heading">Exemplo 1: Mestre Modbus Serial para Monitoramento de Sensores</h3>



<p class="wp-block-paragraph">Um mestre Modbus pode ser utilizado para monitorar parâmetros de sensores conectados via RS-485. O exemplo abaixo ilustra como configurar o mestre para ler a temperatura e umidade de dois dispositivos escravos.</p>



<h4 class="wp-block-heading">Configuração do Mestre:</h4>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="#include &quot;mbcontroller.h&quot;

// Configuração do dicionário de dados
mb_parameter_descriptor_t device_parameters[] = {
    { CID_TEMP, &quot;Temperature&quot;, &quot;C&quot;, MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2, 0, PARAM_TYPE_FLOAT, 4 },
    { CID_HUMID, &quot;Humidity&quot;, &quot;%&quot;, MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 1, 0, PARAM_TYPE_U16, 2 }
};

void app_main() {
    void* master_handler = NULL;
    ESP_ERROR_CHECK(mbc_master_init(MB_PORT_SERIAL_MASTER, &amp;master_handler));

    mb_communication_info_t comm_info = {
        .port = MB_PORT_NUM,
        .mode = MB_MODE_RTU,
        .baudrate = 9600,
        .parity = MB_PARITY_NONE
    };
    ESP_ERROR_CHECK(mbc_master_setup((void*)&amp;comm_info));

    ESP_ERROR_CHECK(mbc_master_set_descriptor(device_parameters, sizeof(device_parameters) / sizeof(device_parameters[0])));
    ESP_ERROR_CHECK(mbc_master_start());

    uint8_t temp_data[4];
    ESP_ERROR_CHECK(mbc_master_get_parameter(CID_TEMP, &quot;Temperature&quot;, temp_data, NULL));
    ESP_LOGI(TAG, &quot;Temperatura lida: %f&quot;, *(float*)temp_data);

    ESP_ERROR_CHECK(mbc_master_destroy());
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">mbcontroller.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Configuração do dicionário de dados</span></span>
<span class="line"><span style="color: #D8DEE9">mb_parameter_descriptor_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">device_parameters</span><span style="color: #D8DEE9FF">[] </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">CID_TEMP</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Temperature</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">C</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_DEVICE_ADDR1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_HOLDING</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">PARAM_TYPE_FLOAT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">CID_HUMID</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Humidity</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">%</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_DEVICE_ADDR1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_INPUT</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">PARAM_TYPE_U16</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">app_main</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">master_handler</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MB_PORT_SERIAL_MASTER</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">master_handler</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">mb_communication_info_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">port</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PORT_NUM</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">mode</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_MODE_RTU</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">baudrate</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">9600</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">parity</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARITY_NONE</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_setup</span><span style="color: #D8DEE9FF">((</span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_set_descriptor</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">device_parameters</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">device_parameters</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">device_parameters</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">])))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_start</span><span style="color: #D8DEE9FF">())</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">temp_data</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">]</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_get_parameter</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">CID_TEMP</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Temperature</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">temp_data</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_LOGI</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">TAG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Temperatura lida: %f</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">float</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">temp_data</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_master_destroy</span><span style="color: #D8DEE9FF">())</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Exemplo 2: Escravo Modbus TCP para Controle de Atuadores</h3>



<p class="wp-block-paragraph">Um escravo Modbus pode ser utilizado para controlar dispositivos como relés ou motores conectados via Ethernet. O exemplo abaixo configura o escravo para gerenciar dois relés.</p>



<h4 class="wp-block-heading">Configuração do Escravo:</h4>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="#include &quot;mbcontroller.h&quot;

#define RELAY_1_GPIO 25
#define RELAY_2_GPIO 26

void app_main() {
    uint16_t relay_registers[2] = {0}; // Registradores para os relés

    mb_register_area_descriptor_t reg_area = {
        .type = MB_PARAM_COIL,
        .start_offset = 0,
        .address = relay_registers,
        .size = sizeof(relay_registers)
    };
    ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));

    mb_communication_info_t comm_info = {
        .ip_port = MB_TCP_PORT,
        .ip_addr_type = MB_IPV4,
        .ip_mode = MB_MODE_TCP,
        .ip_addr = NULL,
        .ip_netif_ptr = esp_netif_ptr
    };
    ESP_ERROR_CHECK(mbc_slave_setup((void*)&amp;comm_info));
    ESP_ERROR_CHECK(mbc_slave_start());

    while (true) {
        if (relay_registers[0]) {
            gpio_set_level(RELAY_1_GPIO, 1);
        }
        if (relay_registers[1]) {
            gpio_set_level(RELAY_2_GPIO, 1);
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }

    ESP_ERROR_CHECK(mbc_slave_destroy());
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">mbcontroller.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">RELAY_1_GPIO</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">25</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">RELAY_2_GPIO</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">26</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">app_main</span><span style="color: #D8DEE9FF">() </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">relay_registers</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF">] </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Registradores para os relés</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">mb_register_area_descriptor_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">reg_area</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">type</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_PARAM_COIL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">start_offset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">address</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">relay_registers</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">size</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">sizeof</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">relay_registers</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_slave_set_descriptor</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">reg_area</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">mb_communication_info_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">ip_port</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_TCP_PORT</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">ip_addr_type</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_IPV4</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">ip_mode</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MB_MODE_TCP</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">ip_addr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">ip_netif_ptr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">esp_netif_ptr</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_slave_setup</span><span style="color: #D8DEE9FF">((</span><span style="color: #81A1C1">void*</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">comm_info</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_slave_start</span><span style="color: #D8DEE9FF">())</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">while</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">true</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">relay_registers</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">]) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">RELAY_1_GPIO</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">relay_registers</span><span style="color: #D8DEE9FF">[</span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">]) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">RELAY_2_GPIO</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">vTaskDelay</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">100</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ESP_ERROR_CHECK</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">mbc_slave_destroy</span><span style="color: #D8DEE9FF">())</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Integração com Outras Tecnologias</h3>



<ul class="wp-block-list">
<li><strong>MQTT:</strong> Combine Modbus com MQTT para enviar dados lidos pelo mestre para um servidor em nuvem.</li>



<li><strong>Automação Industrial:</strong> Use o ESP-Modbus para integrar dispositivos como CLPs e inversores de frequência a um sistema de supervisão (SCADA).</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Conclusão e Próximos Passos</h2>



<p class="wp-block-paragraph">O suporte ao Modbus no ESP32, através da biblioteca ESP-Modbus, oferece uma solução robusta e flexível para aplicações de automação e integração industrial. Seja na leitura de sensores via Modbus RTU ou no controle remoto de dispositivos com Modbus TCP/IP, o ESP-Modbus simplifica a implementação e gerenciamento dessas comunicações.</p>



<h3 class="wp-block-heading">Resumo dos Passos</h3>



<ol class="wp-block-list">
<li><strong>Configuração Inicial:</strong> Defina os parâmetros de comunicação e o mapeamento de dados.</li>



<li><strong>Troca de Dados:</strong> Utilize as APIs para enviar, receber e processar dados entre mestres e escravos.</li>



<li><strong>Diagnóstico e Resolução de Problemas:</strong> Monitore logs e corrija eventuais falhas de comunicação.</li>



<li><strong>Encerramento:</strong> Libere recursos corretamente ao finalizar a aplicação.</li>
</ol>



<h3 class="wp-block-heading">Próximos Passos</h3>



<ul class="wp-block-list">
<li><strong>Integração com Outras Protocolos:</strong> Experimente combinar o Modbus com protocolos como MQTT ou WebSocket para criar sistemas híbridos e conectados.</li>



<li><strong>Escalabilidade:</strong> Explore o uso de redes maiores com múltiplos dispositivos mestre e escravo.</li>



<li><strong>Customização:</strong> Adapte os exemplos fornecidos às suas necessidades específicas, otimizando o desempenho e a confiabilidade.</li>
</ul>



<h3 class="wp-block-heading">Recursos Adicionais</h3>



<p class="wp-block-paragraph">Para mais informações sobre o ESP-Modbus e o ESP-IDF, acesse:</p>



<ul class="wp-block-list">
<li><a href="https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html">Documentação oficial do ESP-IDF</a></li>



<li><a href="https://modbus.org/specs.php">Especificações do protocolo Modbus</a></li>
</ul>



<p class="wp-block-paragraph">Com os exemplos e explicações fornecidos neste artigo, você terá uma base sólida para desenvolver aplicações Modbus em dispositivos ESP32.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"></p><p>The post <a href="https://mcu.tec.br/protoclos/introducao-ao-esp-modbus-com-esp-idf/">Introdução ao ESP-Modbus com ESP-IDF</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">31</post-id>	</item>
		<item>
		<title>Introdução à Biblioteca de Armazenamento Não Volátil (NVS) no ESP32-IDF</title>
		<link>https://mcu.tec.br/microcontroladores/esp32/esp-idf/introducao-a-biblioteca-de-armazenamento-nao-volatil-nvs-no-esp32-idf/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=introducao-a-biblioteca-de-armazenamento-nao-volatil-nvs-no-esp32-idf</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Thu, 26 Dec 2024 02:39:28 +0000</pubDate>
				<category><![CDATA[esp-idf]]></category>
		<category><![CDATA[esp]]></category>
		<category><![CDATA[esp32]]></category>
		<category><![CDATA[idf]]></category>
		<category><![CDATA[nvs]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=13</guid>

					<description><![CDATA[<p>A Biblioteca de Armazenamento Não Volátil (NVS) é uma ferramenta poderosa incluída no framework ESP-IDF, projetada para armazenar dados de forma persistente na memória flash do ESP32. Essa funcionalidade é essencial em sistemas embarcados, pois permite salvar configurações, estados de sensores e outras informações importantes, que permanecem acessíveis mesmo após reinicializações ou falhas de energia. [&#8230;]</p>
<p>The post <a href="https://mcu.tec.br/microcontroladores/esp32/esp-idf/introducao-a-biblioteca-de-armazenamento-nao-volatil-nvs-no-esp32-idf/">Introdução à Biblioteca de Armazenamento Não Volátil (NVS) no ESP32-IDF</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>A <strong>Biblioteca de Armazenamento Não Volátil (NVS)</strong> é uma ferramenta poderosa incluída no framework ESP-IDF, projetada para armazenar dados de forma persistente na memória flash do ESP32. Essa funcionalidade é essencial em sistemas embarcados, pois permite salvar configurações, estados de sensores e outras informações importantes, que permanecem acessíveis mesmo após reinicializações ou falhas de energia.</p>
<hr />
<h4><strong>O que é Armazenamento Não Volátil?</strong></h4>
<p>O termo &#8220;armazenamento não volátil&#8221; refere-se a uma memória que preserva os dados armazenados, mesmo quando não está alimentada por energia. No caso do ESP32, a NVS utiliza uma parte da memória flash para salvar pares de chave-valor. Esse mecanismo é ideal para armazenar pequenas quantidades de dados que precisam ser acessadas com frequência e com alta confiabilidade.</p>
<hr />
<h4><strong>Características Principais da NVS</strong></h4>
<ol>
<li><strong>Armazenamento baseado em pares de chave-valor</strong>:
<ul>
<li>Cada entrada na NVS consiste em uma chave (string ASCII) e um valor.</li>
<li>As chaves podem ter até 15 caracteres.</li>
<li>Os valores suportam tipos como:
<ul>
<li>Inteiros (<code>uint8_t</code>, <code>int16_t</code>, <code>uint32_t</code>, etc.).</li>
<li>Strings (terminadas em nulo).</li>
<li>Blobs (dados binários de tamanho variável).</li>
</ul>
</li>
</ul>
</li>
<li><strong>Organização por espaços de nome (namespaces)</strong>:
<ul>
<li>Os pares chave-valor podem ser organizados em namespaces para evitar conflitos.</li>
<li>Um namespace é uma string ASCII, também limitada a 15 caracteres.</li>
<li>Até 254 namespaces podem ser criados por partição NVS.</li>
</ul>
</li>
<li><strong>Suporte para múltiplos tipos de dados</strong>:
<ul>
<li>A NVS é eficiente para armazenar pequenos valores (como configurações ou contadores).</li>
<li>Para dados maiores, como arquivos, é recomendado usar um sistema de arquivos como FAT.</li>
</ul>
</li>
<li><strong>Robustez e integridade</strong>:
<ul>
<li>A NVS foi projetada para lidar com falhas de energia sem perda de dados.</li>
<li>Em situações críticas, como reinicializações inesperadas, os dados permanecem protegidos, exceto durante a escrita de novos valores.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Implicações do Uso da Memória Flash</strong></h4>
<p>A memória flash, embora seja uma solução confiável para armazenamento persistente, tem uma <strong>vida útil limitada</strong>, contabilizada pelo número de ciclos de <strong>programação e apagamento</strong> (P/E). Cada setor de memória flash pode suportar um número finito de ciclos, geralmente na faixa de 10.000 a 100.000 operações de escrita/apagamento, dependendo do fabricante e do tipo de memória.</p>
<h5><strong>Impactos no Uso da NVS</strong>:</h5>
<ol>
<li><strong>Escritas frequentes podem reduzir a vida útil da memória</strong>:
<ul>
<li>Operações repetidas de escrita (como em contadores) devem ser otimizadas para minimizar o desgaste.</li>
<li>É importante agrupar alterações antes de escrever na NVS.</li>
</ul>
</li>
<li><strong>Fragmentação da memória</strong>:
<ul>
<li>A atualização frequente de valores pode gerar fragmentação, forçando a reorganização e apagamento de setores inteiros para liberar espaço.</li>
</ul>
</li>
<li><strong>Cuidados com a durabilidade</strong>:
<ul>
<li>Para reduzir o desgaste, é recomendado:
<ul>
<li>Usar a NVS apenas para dados que realmente precisam ser persistidos.</li>
<li>Configurar parâmetros que limitem a frequência de escritas, como buffer em memória RAM.</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr />
<p>Você tem razão novamente: depender da RAM para manter o progresso entre reinicializações não é adequado, já que a RAM é volátil e será reiniciada junto com o dispositivo. Para abordar isso corretamente, ajustamos o código para salvar cada incremento diretamente na NVS, enquanto aplicamos técnicas para minimizar o desgaste na memória flash.</p>
<h3><strong>Nova Abordagem: Escrita Otimizada Direta na NVS</strong></h3>
<p>Nessa abordagem, o contador é atualizado e salvo na NVS em cada reinicialização, mas utilizamos estratégias para distribuir o desgaste, como manter o progresso direto sem múltiplos intermediários na RAM.</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include "nvs_flash.h"
#include "nvs.h"

void app_main(void) {
    // Inicializa a NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    // Abre o armazenamento NVS no namespace "storage"
    nvs_handle_t my_handle;
    err = nvs_open("storage", NVS_READWRITE, &amp;my_handle);
    if (err != ESP_OK) {
        printf("Erro ao abrir a NVS!\n");
    } else {
        printf("NVS aberta com sucesso!\n");

        // Lê o contador de reinicializações
        int32_t restart_counter = 0;
        err = nvs_get_i32(my_handle, "restart_counter", &amp;restart_counter);
        switch (err) {
            case ESP_OK:
                printf("Contador de reinicializações lido: %d\n", restart_counter);
                break;
            case ESP_ERR_NVS_NOT_FOUND:
                printf("Contador não inicializado. Configurando para 0.\n");
                restart_counter = 0; // Inicializa o contador
                break;
            default:
                printf("Erro ao ler contador (%s)\n", esp_err_to_name(err));
        }

        // Incrementa o contador
        restart_counter++;
        printf("Incrementando contador: %d\n", restart_counter);

        // Salva o contador na NVS
        err = nvs_set_i32(my_handle, "restart_counter", restart_counter);
        if (err == ESP_OK) {
            printf("Contador salvo na NVS: %d\n", restart_counter);
            err = nvs_commit(my_handle);
            if (err != ESP_OK) {
                printf("Erro ao confirmar gravação (%s)\n", esp_err_to_name(err));
            }
        } else {
            printf("Erro ao salvar contador na NVS (%s)\n", esp_err_to_name(err));
        }

        // Fecha a NVS
        nvs_close(my_handle);
    }

    printf("Contador atualizado. Reinicie o dispositivo para testar novamente.\n");
}
</code></pre>
<hr />
<h3><strong>O que Esta Abordagem Faz?</strong></h3>
<ol>
<li><strong>Persistência Total</strong>:
<ul>
<li>A cada incremento, o valor atualizado é imediatamente salvo na NVS. Isso garante que, mesmo em falhas de energia ou reinicializações inesperadas, o contador reflita o valor real acumulado.</li>
</ul>
</li>
<li><strong>Consideração da Vida Útil da Memória Flash</strong>:
<ul>
<li>Apesar de salvar a cada incremento, o contador evita salvamentos desnecessários ou fragmentação de dados, garantindo eficiência máxima.</li>
<li>Este é o comportamento básico necessário para garantir persistência em sistemas críticos.</li>
</ul>
</li>
<li><strong>Simplicidade de Implementação</strong>:
<ul>
<li>O código lida diretamente com a leitura e escrita da NVS, sem necessidade de lógicas adicionais que dependam da RAM ou outros sistemas voláteis.</li>
</ul>
</li>
</ol>
<hr />
<h3><strong>Implicações e Cuidados</strong></h3>
<ul>
<li><strong>Ciclos de Escrita</strong>:
<ul>
<li>Cada gravação consome um ciclo do tempo de vida da memória flash. Para contadores que incrementam frequentemente (como em reinicializações ou eventos de alta frequência), isso pode levar ao esgotamento mais rápido de setores da memória.</li>
<li>Uma solução para cenários de alta frequência seria implementar buffers de eventos em sistemas complementares, como RTC ou FRAM, e sincronizar periodicamente com a NVS.</li>
</ul>
</li>
<li><strong>Fragmentação</strong>:
<ul>
<li>Como os valores são salvos diretamente, não há riscos de fragmentação de espaço, mas é necessário garantir espaço suficiente para entradas contínuas no setor utilizado pela NVS.</li>
</ul>
</li>
</ul>
<hr />
<p>Caso esta versão esteja adequada, podemos prosseguir para a próxima seção sobre a <strong>estrutura interna da NVS</strong>, onde explicarei como os dados são organizados em páginas e entradas na memória flash. Posso avançar?</p>
<h3><strong>Estrutura Interna da NVS</strong></h3>
<p>A estrutura interna da NVS no ESP32 foi projetada para ser eficiente e robusta, mesmo em casos de uso intenso ou falhas inesperadas. Abaixo, detalhamos como os dados são armazenados, organizados e gerenciados pela biblioteca.</p>
<hr />
<h4><strong>Organização em Páginas e Entradas</strong></h4>
<p>A NVS utiliza um modelo baseado em <strong>páginas</strong> e <strong>entradas</strong> para gerenciar os pares de chave-valor armazenados na memória flash.</p>
<ol>
<li><strong>Páginas</strong>:
<ul>
<li>Cada página corresponde a um <strong>setor lógico</strong> na memória flash, geralmente com 4 KB (tamanho padrão de um setor em dispositivos ESP32).</li>
<li>As páginas têm estados específicos que refletem sua utilidade:
<ul>
<li><strong>Vazia</strong>: Nenhum dado foi gravado ainda.</li>
<li><strong>Ativa</strong>: Dados estão sendo gravados, e há espaço livre disponível.</li>
<li><strong>Cheia</strong>: Todos os espaços disponíveis foram utilizados.</li>
<li><strong>Corrompida</strong>: O cabeçalho ou os dados da página estão inválidos e não podem ser usados.</li>
</ul>
</li>
<li>Páginas em uso possuem um número de sequência, indicando a ordem de criação.</li>
</ul>
</li>
<li><strong>Entradas</strong>:
<ul>
<li>Cada entrada armazena um único par de chave-valor ou parte dele.</li>
<li>Uma entrada ocupa 32 bytes, alinhada com os requisitos de criptografia e eficiência da flash.</li>
<li>Para valores grandes (strings ou blobs), as entradas podem ser divididas em várias partes.</li>
</ul>
</li>
</ol>
<h4><strong>Como os Dados São Gravados</strong></h4>
<ul>
<li><strong>Gravação Incremental</strong>:
<ul>
<li>Novos pares de chave-valor são adicionados ao final da página ativa.</li>
<li>Atualizações não sobrescrevem valores existentes; em vez disso, uma nova entrada é adicionada, e a antiga é marcada como apagada.</li>
</ul>
</li>
<li><strong>Reaproveitamento de Espaço</strong>:
<ul>
<li>Quando uma página está cheia, a NVS move as entradas não apagadas para outra página antes de limpar a atual. Isso evita perda de dados.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>Exemplo de Estados de Página</strong></h4>
<p>O exemplo abaixo ilustra os estados de quatro páginas em uso:</p>
<pre><code>+--------+     +--------+     +--------+     +--------+
| Página 1 |     | Página 2 |     | Página 3 |     | Página 4 |
| Cheia   |     | Cheia   |     | Ativa   |     | Vazia   |
| Seq #11 |     | Seq #12 |     | Seq #14 |     |        |
+---+----+     +----+---+     +----+---+     +---+----+
</code></pre>
<ol>
<li><strong>Página Cheia (1 e 2)</strong>:
<ul>
<li>Não pode receber novas gravações, mas as entradas ainda podem ser lidas.</li>
</ul>
</li>
<li><strong>Página Ativa (3)</strong>:
<ul>
<li>Dados podem ser gravados até que o espaço acabe.</li>
</ul>
</li>
<li><strong>Página Vazia (4)</strong>:
<ul>
<li>Reservada para uso futuro.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Estrutura de uma Página</strong></h4>
<p>Uma página é dividida em três partes principais:</p>
<ol>
<li><strong>Cabeçalho</strong>:
<ul>
<li>Contém metadados, como o estado da página, número de sequência, versão e checksum (CRC32) para verificar integridade.</li>
</ul>
</li>
<li><strong>Bitmap de Estado de Entradas</strong>:
<ul>
<li>Um mapa que indica o estado de cada entrada:
<ul>
<li><strong>Vazia</strong>: Nenhum dado foi gravado.</li>
<li><strong>Escrita</strong>: Dados válidos estão presentes.</li>
<li><strong>Apagada</strong>: A entrada foi descartada.</li>
</ul>
</li>
</ul>
</li>
<li><strong>Entradas</strong>:
<ul>
<li>Dados reais armazenados, incluindo chave, valor e tipo.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Exemplo de Gravação</strong></h4>
<p>Abaixo está uma simulação de como os dados são armazenados:</p>
<pre><code class="language-text">+-----------+--------------+-------------+------------------------+--------+
| Cabeçalho | Bitmap de Estado | Entrada 1  | Entrada 2             | ...    |
+-----------+--------------+-------------+------------------------+--------+
</code></pre>
<ul>
<li><strong>Entrada 1</strong>:
<ul>
<li>Tipo: Inteiro (4 bytes).</li>
<li>Dados: <code>restart_counter = 10</code>.</li>
</ul>
</li>
<li><strong>Entrada 2</strong>:
<ul>
<li>Tipo: String (16 bytes).</li>
<li>Dados: <code>"SSID do Wi-Fi"</code>.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>Impacto nos Ciclos de Vida da Flash</strong></h4>
<p>A organização da NVS minimiza o desgaste da memória flash ao evitar gravações desnecessárias e reaproveitar setores apenas quando necessário. No entanto:</p>
<ul>
<li>A repetida atualização de valores pequenos pode encher páginas rapidamente, levando ao apagamento frequente.</li>
<li>Para mitigar isso, considere agrupar alterações ou usar buffers.</li>
</ul>
<hr />
<h3><strong>Namespaces na NVS</strong></h3>
<p>A biblioteca NVS oferece um mecanismo chamado <strong>namespaces</strong> (espaços de nome) para organizar os dados armazenados e evitar conflitos entre diferentes módulos ou partes de uma aplicação. Essa funcionalidade é especialmente útil em projetos complexos, onde vários subsistemas podem precisar salvar dados na memória flash.</p>
<hr />
<h4><strong>O que são Namespaces?</strong></h4>
<p>Namespaces são <strong>contêineres lógicos</strong> que agrupam pares de chave-valor na NVS. Cada namespace possui um nome único e segue as mesmas regras de nomenclatura das chaves:</p>
<ul>
<li><strong>Limite de caracteres</strong>: 15 caracteres ASCII.</li>
<li><strong>Unicidade</strong>: Cada namespace deve ter um nome único dentro de uma partição NVS.</li>
</ul>
<p>Com namespaces, diferentes módulos da aplicação podem usar as mesmas chaves sem sobrescrever os dados uns dos outros.</p>
<hr />
<h4><strong>Características Principais</strong></h4>
<ol>
<li><strong>Isolamento de Dados</strong>:
<ul>
<li>Os dados em um namespace são isolados dos dados em outros namespaces, evitando conflitos de chave.</li>
</ul>
</li>
<li><strong>Suporte a Múltiplos Namespaces</strong>:
<ul>
<li>Cada partição NVS pode suportar até <strong>254 namespaces diferentes</strong>.</li>
</ul>
</li>
<li><strong>Identificação Única</strong>:
<ul>
<li>O namespace é especificado durante a inicialização de uma operação de leitura ou gravação.</li>
</ul>
</li>
<li><strong>Uso em Múltiplas Partições</strong>:
<ul>
<li>Namespaces com o mesmo nome, mas em partições diferentes, são considerados independentes.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Como Usar Namespaces na NVS</strong></h4>
<p>O uso de namespaces requer a abertura de um &#8220;handle&#8221; para um namespace específico antes de acessar os dados. Abaixo está um exemplo prático:</p>
<h5><strong>Exemplo de Uso de Namespaces</strong></h5>
<p>No exemplo abaixo, dois módulos diferentes armazenam dados no mesmo dispositivo, mas em namespaces separados:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include "nvs_flash.h"
#include "nvs.h"

void app_main(void) {
    // Inicializa a NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    // Modulo 1: Armazena configuração de Wi-Fi no namespace "wifi"
    nvs_handle_t wifi_handle;
    err = nvs_open("wifi", NVS_READWRITE, &amp;wifi_handle);
    if (err == ESP_OK) {
        printf("Namespace 'wifi' aberto com sucesso!\n");

        // Salva o SSID
        const char *ssid = "Rede-WiFi";
        err = nvs_set_str(wifi_handle, "ssid", ssid);
        if (err == ESP_OK) {
            printf("SSID salvo: %s\n", ssid);
            nvs_commit(wifi_handle);
        }

        nvs_close(wifi_handle);
    }

    // Modulo 2: Armazena configuração de PWM no namespace "pwm"
    nvs_handle_t pwm_handle;
    err = nvs_open("pwm", NVS_READWRITE, &amp;pwm_handle);
    if (err == ESP_OK) {
        printf("Namespace 'pwm' aberto com sucesso!\n");

        // Salva a frequência do PWM
        uint16_t pwm_freq = 1000; // 1 kHz
        err = nvs_set_u16(pwm_handle, "frequency", pwm_freq);
        if (err == ESP_OK) {
            printf("Frequência PWM salva: %d Hz\n", pwm_freq);
            nvs_commit(pwm_handle);
        }

        nvs_close(pwm_handle);
    }

    printf("Dados salvos em namespaces diferentes.\n");
}
</code></pre>
<hr />
<h4><strong>Explicação do Código</strong></h4>
<ol>
<li><strong>Namespace <code>wifi</code></strong>:
<ul>
<li>Utilizado para armazenar o <strong>SSID</strong> de uma rede Wi-Fi.</li>
<li>O par chave-valor <code>"ssid"</code> é salvo nesse namespace.</li>
</ul>
</li>
<li><strong>Namespace <code>pwm</code></strong>:
<ul>
<li>Utilizado para armazenar a <strong>frequência de PWM</strong> de um módulo.</li>
<li>O par chave-valor <code>"frequency"</code> é salvo nesse namespace.</li>
</ul>
</li>
<li><strong>Isolamento</strong>:
<ul>
<li>Os dados salvos no namespace <code>wifi</code> são completamente independentes dos dados salvos no namespace <code>pwm</code>. Mesmo que ambos usem a chave <code>"frequency"</code>, os valores não colidem.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Práticas Recomendadas</strong></h4>
<ul>
<li><strong>Nomeação de Namespaces</strong>:
<ul>
<li>Use nomes descritivos e curtos, como <code>wifi</code>, <code>sensor</code>, <code>config</code>.</li>
</ul>
</li>
<li><strong>Organização de Dados</strong>:
<ul>
<li>Defina namespaces para diferentes módulos ou subsistemas (ex.: um namespace para sensores, outro para configurações de rede).</li>
</ul>
</li>
<li><strong>Gerenciamento de Recursos</strong>:
<ul>
<li>Sempre feche os handles de namespace com <code>nvs_close()</code> após concluir as operações.</li>
</ul>
</li>
</ul>
<hr />
<h3><strong>Uso da API NVS para Leitura e Gravação</strong></h3>
<p>A API da NVS (Non-Volatile Storage) no ESP32-IDF fornece um conjunto robusto de funções para manipular dados armazenados na memória flash. Essas funções permitem gravar, ler e apagar pares de chave-valor, garantindo a persistência dos dados em diversas aplicações.</p>
<hr />
<h4><strong>Funções Principais da API</strong></h4>
<p>Abaixo estão as funções mais utilizadas na NVS para leitura e gravação, organizadas por operação:</p>
<ol>
<li><strong>Inicialização e Fechamento</strong>:
<ul>
<li><code>nvs_flash_init()</code>: Inicializa o sistema NVS.</li>
<li><code>nvs_flash_erase()</code>: Apaga todo o conteúdo da partição NVS.</li>
<li><code>nvs_open()</code>: Abre um namespace para leitura/escrita.</li>
<li><code>nvs_close()</code>: Fecha o handle do namespace.</li>
</ul>
</li>
<li><strong>Gravação de Dados</strong>:
<ul>
<li><code>nvs_set_*()</code>: Define o valor de uma chave (<code>set_i8</code>, <code>set_u32</code>, <code>set_str</code>, etc.).</li>
<li><code>nvs_commit()</code>: Garante que as alterações sejam persistidas.</li>
</ul>
</li>
<li><strong>Leitura de Dados</strong>:
<ul>
<li><code>nvs_get_*()</code>: Obtém o valor de uma chave (<code>get_i8</code>, <code>get_u32</code>, <code>get_str</code>, etc.).</li>
</ul>
</li>
<li><strong>Apagar Dados</strong>:
<ul>
<li><code>nvs_erase_key()</code>: Remove uma chave específica.</li>
<li><code>nvs_erase_all()</code>: Remove todas as chaves de um namespace.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Exemplo Básico: Gravação e Leitura</strong></h4>
<p>O exemplo abaixo demonstra como gravar e recuperar diferentes tipos de dados na NVS.</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include "nvs_flash.h"
#include "nvs.h"

void app_main(void) {
    // Inicializa a NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    // Abre o namespace "storage" no modo leitura/escrita
    nvs_handle_t my_handle;
    err = nvs_open("storage", NVS_READWRITE, &amp;my_handle);
    if (err != ESP_OK) {
        printf("Erro ao abrir o namespace NVS!\n");
        return;
    }

    // Grava diferentes tipos de dados
    printf("Gravando valores na NVS...\n");
    err = nvs_set_i32(my_handle, "int_key", 42);
    if (err == ESP_OK) printf("Inteiro salvo com sucesso!\n");

    err = nvs_set_str(my_handle, "str_key", "ESP32-IDF");
    if (err == ESP_OK) printf("String salva com sucesso!\n");

    float float_value = 3.14159f;
    err = nvs_set_blob(my_handle, "blob_key", &amp;float_value, sizeof(float));
    if (err == ESP_OK) printf("Blob salvo com sucesso!\n");

    // Confirma a gravação
    err = nvs_commit(my_handle);
    if (err == ESP_OK) {
        printf("Alterações confirmadas na NVS.\n");
    }

    // Lê os dados gravados
    printf("Lendo valores da NVS...\n");
    int32_t int_value;
    err = nvs_get_i32(my_handle, "int_key", &amp;int_value);
    if (err == ESP_OK) printf("Inteiro lido: %d\n", int_value);

    char str_value[20];
    size_t str_len = sizeof(str_value);
    err = nvs_get_str(my_handle, "str_key", str_value, &amp;str_len);
    if (err == ESP_OK) printf("String lida: %s\n", str_value);

    float read_blob;
    size_t blob_size = sizeof(read_blob);
    err = nvs_get_blob(my_handle, "blob_key", &amp;read_blob, &amp;blob_size);
    if (err == ESP_OK) printf("Blob lido: %.5f\n", read_blob);

    // Fecha o handle
    nvs_close(my_handle);
    printf("Operações concluídas.\n");
}
</code></pre>
<hr />
<h4><strong>Explicação do Código</strong></h4>
<ol>
<li><strong>Inicialização da NVS</strong>:
<ul>
<li><code>nvs_flash_init()</code> prepara a memória flash para operações.</li>
<li>Em caso de erro, como falta de páginas livres, a memória é apagada e reinicializada.</li>
</ul>
</li>
<li><strong>Gravação de Dados</strong>:
<ul>
<li><code>nvs_set_i32()</code> grava um número inteiro.</li>
<li><code>nvs_set_str()</code> grava uma string terminada em nulo.</li>
<li><code>nvs_set_blob()</code> grava um bloco binário, como um valor float.</li>
</ul>
</li>
<li><strong>Leitura de Dados</strong>:
<ul>
<li><code>nvs_get_i32()</code> recupera um número inteiro.</li>
<li><code>nvs_get_str()</code> recupera uma string, usando um buffer para armazenamento.</li>
<li><code>nvs_get_blob()</code> recupera um blob, especificando o tamanho.</li>
</ul>
</li>
<li><strong>Persistência Garantida</strong>:
<ul>
<li><code>nvs_commit()</code> assegura que as gravações sejam salvas definitivamente.</li>
</ul>
</li>
<li><strong>Fechamento</strong>:
<ul>
<li><code>nvs_close()</code> libera recursos associados ao handle.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Tratamento de Erros</strong></h4>
<p>A API retorna códigos de erro em caso de falhas, como:</p>
<ul>
<li><code>ESP_ERR_NVS_NOT_FOUND</code>: A chave não existe.</li>
<li><code>ESP_ERR_NVS_INVALID_HANDLE</code>: O handle foi fechado ou é inválido.</li>
<li><code>ESP_ERR_NVS_NOT_ENOUGH_SPACE</code>: Espaço insuficiente para gravar o valor.</li>
</ul>
<hr />
<h4><strong>Práticas Recomendadas</strong></h4>
<ul>
<li>Sempre use <code>nvs_commit()</code> após gravações para garantir persistência.</li>
<li>Verifique os códigos de erro ao ler ou gravar dados.</li>
<li>Use buffers apropriados para leitura de strings e blobs.</li>
</ul>
<hr />
<h3><strong>Exemplos Avançados com Strings e Blobs na NVS</strong></h3>
<p>Strings e blobs (dados binários de tamanho variável) são tipos de dados amplamente utilizados na NVS. Esses tipos permitem armazenar informações como textos e estruturas complexas em formatos binários.</p>
<p>Nesta seção, exploraremos como trabalhar com esses tipos de dados de maneira eficiente e segura.</p>
<hr />
<h4><strong>Armazenando e Recuperando Strings</strong></h4>
<p>Strings são armazenadas na NVS como valores terminados em nulo. A função <code>nvs_set_str()</code> grava uma string, enquanto <code>nvs_get_str()</code> a recupera.</p>
<h5><strong>Exemplo Prático: Salvando e Lendo Strings</strong></h5>
<p>No exemplo abaixo, salvamos e recuperamos o nome de um dispositivo:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include "nvs_flash.h"
#include "nvs.h"

void app_main(void) {
    // Inicializa a NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    // Abre o namespace "storage"
    nvs_handle_t my_handle;
    err = nvs_open("storage", NVS_READWRITE, &amp;my_handle);
    ESP_ERROR_CHECK(err);

    // Grava uma string
    const char *device_name = "ESP32-Device";
    err = nvs_set_str(my_handle, "device_name", device_name);
    if (err == ESP_OK) {
        printf("Nome do dispositivo salvo: %s\n", device_name);
        nvs_commit(my_handle);
    }

    // Lê a string gravada
    char buffer[50];
    size_t required_size = sizeof(buffer);
    err = nvs_get_str(my_handle, "device_name", buffer, &amp;required_size);
    if (err == ESP_OK) {
        printf("Nome do dispositivo lido: %s\n", buffer);
    }

    // Fecha o namespace
    nvs_close(my_handle);
}
</code></pre>
<hr />
<h4><strong>Explicação do Código</strong></h4>
<ol>
<li><strong>Gravação de String</strong>:
<ul>
<li><code>nvs_set_str()</code> grava uma string no par chave-valor.</li>
<li>A string é armazenada de forma compacta na NVS.</li>
</ul>
</li>
<li><strong>Leitura de String</strong>:
<ul>
<li><code>nvs_get_str()</code> recupera a string.</li>
<li>É necessário passar um buffer para armazenar a string e informar o tamanho.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Armazenando e Recuperando Blobs</strong></h4>
<p>Blobs (Binary Large Objects) são usados para armazenar dados binários arbitrários, como estruturas, arrays ou objetos codificados.</p>
<h5><strong>Exemplo Prático: Salvando e Lendo Blobs</strong></h5>
<p>No exemplo abaixo, salvamos e lemos uma estrutura de configuração:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include "nvs_flash.h"
#include "nvs.h"

typedef struct {
    int32_t baud_rate;
    uint8_t parity;
    uint8_t stop_bits;
} uart_config_t;

void app_main(void) {
    // Inicializa a NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    // Abre o namespace "config"
    nvs_handle_t my_handle;
    err = nvs_open("config", NVS_READWRITE, &amp;my_handle);
    ESP_ERROR_CHECK(err);

    // Grava um blob
    uart_config_t uart_config = {115200, 0, 1};
    err = nvs_set_blob(my_handle, "uart_cfg", &amp;uart_config, sizeof(uart_config));
    if (err == ESP_OK) {
        printf("Configuração UART salva.\n");
        nvs_commit(my_handle);
    }

    // Lê o blob gravado
    uart_config_t read_config;
    size_t blob_size = sizeof(read_config);
    err = nvs_get_blob(my_handle, "uart_cfg", &amp;read_config, &amp;blob_size);
    if (err == ESP_OK) {
        printf("Configuração UART lida: Baud Rate = %d, Paridade = %d, Stop Bits = %d\n",
               read_config.baud_rate, read_config.parity, read_config.stop_bits);
    }

    // Fecha o namespace
    nvs_close(my_handle);
}
</code></pre>
<hr />
<h4><strong>Explicação do Código</strong></h4>
<ol>
<li><strong>Gravação de Blob</strong>:
<ul>
<li><code>nvs_set_blob()</code> grava o blob. É necessário informar o ponteiro para os dados e o tamanho.</li>
</ul>
</li>
<li><strong>Leitura de Blob</strong>:
<ul>
<li><code>nvs_get_blob()</code> recupera o blob. O tamanho deve ser conhecido e informado para alocar memória adequadamente.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Práticas Recomendadas</strong></h4>
<ol>
<li><strong>Gerenciamento de Buffers</strong>:
<ul>
<li>Sempre use buffers de tamanho adequado ao armazenar e recuperar strings ou blobs.</li>
</ul>
</li>
<li><strong>Verificação de Erros</strong>:
<ul>
<li>Cheque os códigos de erro retornados pelas funções da NVS, como <code>ESP_ERR_NVS_NOT_FOUND</code> (chave não encontrada).</li>
</ul>
</li>
<li><strong>Reduza a Fragmentação</strong>:
<ul>
<li>Evite gravar blobs muito grandes para minimizar a fragmentação na NVS.</li>
</ul>
</li>
</ol>
<hr />
<h3><strong>Segurança e Criptografia na NVS</strong></h3>
<p>A segurança dos dados armazenados em dispositivos embarcados é uma preocupação fundamental, especialmente em aplicações que lidam com informações sensíveis, como credenciais de rede, chaves de API ou configurações críticas do sistema. A NVS (Non-Volatile Storage) no ESP32 oferece suporte à criptografia para proteger os dados armazenados.</p>
<hr />
<h4><strong>Como Funciona a Criptografia na NVS</strong></h4>
<ol>
<li><strong>Integração com a Criptografia de Flash do ESP32</strong>:
<ul>
<li>A NVS utiliza a <strong>criptografia de flash</strong> nativa do ESP32 para proteger os dados armazenados.</li>
<li>Com a criptografia habilitada, os dados gravados na NVS são cifrados automaticamente antes de serem armazenados na memória flash.</li>
</ul>
</li>
<li><strong>Chaves de Criptografia</strong>:
<ul>
<li>As chaves de criptografia usadas pela NVS são armazenadas de forma segura em uma partição dedicada (<code>nvs_keys</code>).</li>
<li>Se essa partição estiver vazia, novas chaves serão geradas automaticamente durante a inicialização.</li>
</ul>
</li>
<li><strong>Transparência para o Desenvolvedor</strong>:
<ul>
<li>A API da NVS permanece a mesma, independentemente de a criptografia estar habilitada ou não.</li>
<li>As operações de leitura e gravação são tratadas de forma transparente, sem necessidade de ajustes no código.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Habilitando a Criptografia na NVS</strong></h4>
<p>Para ativar a criptografia na NVS, é necessário configurar o projeto no <strong>menuconfig</strong> do ESP-IDF:</p>
<ol>
<li>Acesse o <strong>menuconfig</strong>:
<pre><code class="language-bash">idf.py menuconfig
</code></pre>
</li>
<li>Navegue até:
<pre><code>Component config -&gt; NVS -&gt; Enable NVS encryption
</code></pre>
</li>
<li>Ative a opção <strong>Enable NVS encryption</strong>.</li>
<li>Certifique-se de que a partição <code>nvs_keys</code> esteja definida na tabela de partições. Um exemplo de entrada na tabela seria:
<pre><code>nvs_keys,      data, nvs_keys,   0x6000,   0x1000
</code></pre>
</li>
</ol>
<hr />
<h4><strong>Exemplo de Código: Inicialização com Criptografia</strong></h4>
<p>O exemplo abaixo mostra como inicializar a NVS com criptografia habilitada:</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include "nvs_flash.h"
#include "nvs.h"

void app_main(void) {
    // Inicializa a NVS com suporte à criptografia
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    printf("NVS inicializada com criptografia habilitada.\n");

    // Abre o namespace "secure_data"
    nvs_handle_t my_handle;
    err = nvs_open("secure_data", NVS_READWRITE, &amp;my_handle);
    if (err == ESP_OK) {
        printf("Namespace 'secure_data' aberto com sucesso!\n");

        // Grava uma string segura
        const char *secure_key = "my_secure_key";
        err = nvs_set_str(my_handle, "api_key", secure_key);
        if (err == ESP_OK) {
            printf("Chave segura salva: %s\n", secure_key);
            nvs_commit(my_handle);
        }

        // Fecha o handle
        nvs_close(my_handle);
    } else {
        printf("Erro ao abrir o namespace 'secure_data'.\n");
    }
}
</code></pre>
<hr />
<h4><strong>Benefícios da Criptografia na NVS</strong></h4>
<ol>
<li><strong>Proteção contra Acessos Não Autorizados</strong>:
<ul>
<li>Mesmo que alguém tenha acesso físico ao chip, os dados permanecem cifrados e ilegíveis sem as chaves.</li>
</ul>
</li>
<li><strong>Compatibilidade com as APIs Existentes</strong>:
<ul>
<li>A criptografia é habilitada sem necessidade de alterações significativas no código.</li>
</ul>
</li>
<li><strong>Robustez contra Manipulações</strong>:
<ul>
<li>Dados alterados ou corrompidos de forma maliciosa serão invalidados pela NVS.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Limitações</strong></h4>
<ol>
<li><strong>Ausência de Resistência a Apagamento</strong>:
<ul>
<li>A criptografia protege contra leitura e modificação não autorizada, mas não impede que dados sejam apagados.</li>
</ul>
</li>
<li><strong>Requisitos de Memória</strong>:
<ul>
<li>O uso de criptografia pode aumentar levemente o consumo de memória RAM e CPU devido ao processamento criptográfico.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Práticas Recomendadas</strong></h4>
<ol>
<li><strong>Gerenciamento de Chaves</strong>:
<ul>
<li>Sempre garanta que a partição <code>nvs_keys</code> esteja protegida e não seja compartilhada entre dispositivos.</li>
</ul>
</li>
<li><strong>Reinicialização de Chaves</strong>:
<ul>
<li>Em caso de suspeita de comprometimento, apague a partição e deixe o sistema regenerar novas chaves.</li>
</ul>
</li>
<li><strong>Teste Extensivo</strong>:
<ul>
<li>Certifique-se de testar a inicialização e leitura da NVS em dispositivos configurados com criptografia habilitada.</li>
</ul>
</li>
</ol>
<h3><strong>Diagnóstico e Depuração na NVS</strong></h3>
<p>A NVS no ESP32 oferece ferramentas e métodos para diagnosticar e depurar problemas relacionados ao armazenamento de dados. Esses mecanismos são importantes para identificar e corrigir erros durante o desenvolvimento ou em aplicações em produção.</p>
<hr />
<h4><strong>Principais Problemas e Soluções</strong></h4>
<ol>
<li><strong>Chaves Não Encontradas</strong>:
<ul>
<li><strong>Erro</strong>: <code>ESP_ERR_NVS_NOT_FOUND</code>.</li>
<li><strong>Causa</strong>: A chave especificada não existe no namespace ou foi apagada.</li>
<li><strong>Solução</strong>:
<ul>
<li>Verifique se a chave foi escrita corretamente.</li>
<li>Certifique-se de que o namespace está inicializado.</li>
</ul>
</li>
</ul>
</li>
<li><strong>Armazenamento Corrompido</strong>:
<ul>
<li><strong>Erro</strong>: <code>ESP_ERR_NVS_INVALID_STATE</code> ou comportamento inesperado.</li>
<li><strong>Causa</strong>: Dados na flash foram corrompidos, possivelmente devido a falhas de energia durante gravações.</li>
<li><strong>Solução</strong>:
<ul>
<li>Apague e reinicialize a partição NVS usando <code>nvs_flash_erase()</code>.</li>
</ul>
</li>
</ul>
</li>
<li><strong>Falta de Espaço na NVS</strong>:
<ul>
<li><strong>Erro</strong>: <code>ESP_ERR_NVS_NOT_ENOUGH_SPACE</code>.</li>
<li><strong>Causa</strong>: A partição está cheia ou há fragmentação excessiva.</li>
<li><strong>Solução</strong>:
<ul>
<li>Otimize o uso da NVS para evitar gravações excessivas.</li>
<li>Aumente o tamanho da partição na tabela de partições.</li>
</ul>
</li>
</ul>
</li>
<li><strong>Partição Não Inicializada</strong>:
<ul>
<li><strong>Erro</strong>: <code>ESP_ERR_NVS_NOT_INITIALIZED</code>.</li>
<li><strong>Causa</strong>: A partição NVS não foi inicializada antes de realizar operações.</li>
<li><strong>Solução</strong>:
<ul>
<li>Certifique-se de chamar <code>nvs_flash_init()</code> antes de qualquer operação com a NVS.</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Funções para Diagnóstico</strong></h4>
<p>A NVS oferece funções específicas para verificar o estado e o uso da memória:</p>
<ol>
<li><strong><code>nvs_get_stats()</code></strong>:
<ul>
<li>Obtém estatísticas sobre a partição NVS, como número de entradas usadas, livres e totais.</li>
<li><strong>Exemplo</strong>:
<pre><code class="language-c">#include "nvs.h"

void print_nvs_stats(const char *part_name) {
    nvs_stats_t stats;
    esp_err_t err = nvs_get_stats(part_name, &amp;stats);
    if (err == ESP_OK) {
        printf("Estatísticas da NVS:\n");
        printf("Entradas usadas: %lu\n", stats.used_entries);
        printf("Entradas livres: %lu\n", stats.free_entries);
        printf("Entradas totais: %lu\n", stats.total_entries);
        printf("Namespaces: %lu\n", stats.namespace_count);
    } else {
        printf("Erro ao obter estatísticas da NVS.\n");
    }
}
</code></pre>
</li>
</ul>
</li>
<li><strong><code>nvs_get_used_entry_count()</code></strong>:
<ul>
<li>Obtém o número de entradas usadas em um namespace específico.</li>
<li><strong>Exemplo</strong>:
<pre><code class="language-c">void print_namespace_entries(nvs_handle_t handle) {
    size_t used_entries = 0;
    esp_err_t err = nvs_get_used_entry_count(handle, &amp;used_entries);
    if (err == ESP_OK) {
        printf("Entradas usadas no namespace: %lu\n", used_entries);
    } else {
        printf("Erro ao obter contagem de entradas: %s\n", esp_err_to_name(err));
    }
}
</code></pre>
</li>
</ul>
</li>
<li><strong><code>nvs_entry_find()</code> e Iteradores</strong>:
<ul>
<li>Lista todas as chaves e valores armazenados em um namespace ou partição.</li>
<li><strong>Exemplo</strong>:
<pre><code class="language-c">void list_all_entries(const char *part_name, const char *namespace) {
    nvs_iterator_t it = NULL;
    esp_err_t err = nvs_entry_find(part_name, namespace, NVS_TYPE_ANY, &amp;it);
    while (err == ESP_OK &amp;&amp; it != NULL) {
        nvs_entry_info_t info;
        nvs_entry_info(it, &amp;info);
        printf("Namespace: %s, Chave: %s, Tipo: %d\n", info.namespace_name, info.key, info.type);
        err = nvs_entry_next(&amp;it);
    }
    nvs_release_iterator(it);
}
</code></pre>
</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Depurando Passo a Passo</strong></h4>
<ol>
<li><strong>Inicialização</strong>:
<ul>
<li>Verifique se <code>nvs_flash_init()</code> é chamado no início do programa.</li>
<li>Certifique-se de que a tabela de partições está configurada corretamente.</li>
</ul>
</li>
<li><strong>Testes de Gravação e Leitura</strong>:
<ul>
<li>Teste com pequenos pares de chave-valor para garantir que a partição NVS está funcional.</li>
<li>Use <code>nvs_commit()</code> após gravações para garantir persistência.</li>
</ul>
</li>
<li><strong>Monitoramento de Espaço</strong>:
<ul>
<li>Utilize <code>nvs_get_stats()</code> regularmente para monitorar o uso e identificar problemas de fragmentação.</li>
</ul>
</li>
<li><strong>Logs Detalhados</strong>:
<ul>
<li>Habilite logs detalhados no menuconfig:
<pre><code>Component config -&gt; NVS -&gt; Enable debug logs
</code></pre>
</li>
<li>Isso ajuda a identificar falhas em operações de leitura e gravação.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Práticas Recomendadas para Diagnóstico</strong></h4>
<ul>
<li>Sempre trate os erros retornados pelas funções da NVS.</li>
<li>Antes de apagar a NVS, realize backups dos dados críticos.</li>
<li>Execute testes regulares em dispositivos reais para identificar problemas de comportamento.</li>
</ul>
<hr />
<h3><strong>Internals da NVS: Logs e Mecanismos de Paginação</strong></h3>
<p>A arquitetura interna da NVS foi projetada para ser eficiente e confiável, utilizando um sistema baseado em logs e paginação para organizar os dados armazenados. Esta abordagem permite operações robustas mesmo em condições adversas, como falhas de energia ou acessos frequentes.</p>
<hr />
<h4><strong>Armazenamento Baseado em Logs</strong></h4>
<p>A NVS usa um modelo de armazenamento sequencial, onde novos dados são adicionados ao final de um log. Isso significa que:</p>
<ol>
<li><strong>Escrita Não Sobrescreve Dados</strong>:
<ul>
<li>Quando um valor é atualizado, a nova versão é gravada no final do log, enquanto a entrada antiga é marcada como apagada.</li>
<li>Esse modelo minimiza o desgaste da memória flash ao evitar reescritas frequentes em setores já utilizados.</li>
</ul>
</li>
<li><strong>Organização das Entradas</strong>:
<ul>
<li>Cada entrada no log contém:
<ul>
<li>Uma chave única.</li>
<li>Um valor associado.</li>
<li>Metadados, como tipo de dado e informações de integridade.</li>
</ul>
</li>
</ul>
</li>
<li><strong>Compactação</strong>:
<ul>
<li>Quando um log fica cheio ou fragmentado, a NVS move os dados válidos para uma nova página, liberando espaço para novas gravações.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Mecanismo de Paginação</strong></h4>
<p>O armazenamento da NVS é dividido em páginas, que são setores lógicos da memória flash, geralmente de 4 KB cada.</p>
<ol>
<li><strong>Estados das Páginas</strong>:
<ul>
<li><strong>Vazia</strong>: Nenhuma gravação foi feita.</li>
<li><strong>Ativa</strong>: Dados estão sendo gravados; ainda há espaço disponível.</li>
<li><strong>Cheia</strong>: A página atingiu sua capacidade máxima.</li>
<li><strong>Corrompida</strong>: Dados inválidos ou inconsistentes; a página não é utilizada.</li>
</ul>
</li>
<li><strong>Gerenciamento de Páginas</strong>:
<ul>
<li>Páginas em uso possuem números de sequência, permitindo que a NVS determine a ordem de gravação.</li>
<li>Páginas corrompidas são ignoradas durante as operações de leitura.</li>
</ul>
</li>
<li><strong>Estrutura de Página</strong>:
<ul>
<li><strong>Cabeçalho</strong>:
<ul>
<li>Inclui informações como estado da página, número de sequência e checksum.</li>
</ul>
</li>
<li><strong>Entradas</strong>:
<ul>
<li>Dados reais armazenados em blocos de 32 bytes.</li>
</ul>
</li>
<li><strong>Bitmap de Estado</strong>:
<ul>
<li>Indica se uma entrada está vazia, ocupada ou apagada.</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Exemplo de Organização Interna</strong></h4>
<p>Imagine um cenário com quatro páginas na NVS:</p>
<pre><code>+--------+     +--------+     +--------+     +--------+
| Página 1 |     | Página 2 |     | Página 3 |     | Página 4 |
| Cheia   |     | Cheia   |     | Ativa   |     | Vazia   |
| Seq #10 |     | Seq #11 |     | Seq #12 |     |        |
+---+----+     +----+---+     +----+---+     +---+----+
</code></pre>
<ul>
<li><strong>Página 1 e 2</strong>:
<ul>
<li>Contêm dados completos, mas não podem receber novas gravações.</li>
</ul>
</li>
<li><strong>Página 3</strong>:
<ul>
<li>Está ativa e pode gravar novos pares de chave-valor.</li>
</ul>
</li>
<li><strong>Página 4</strong>:
<ul>
<li>Está vazia e será usada quando a Página 3 estiver cheia.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>Benefícios do Modelo</strong></h4>
<ol>
<li><strong>Minimiza o Desgaste da Flash</strong>:
<ul>
<li>Como os dados são gravados sequencialmente, as operações de apagamento são realizadas apenas quando necessário.</li>
</ul>
</li>
<li><strong>Resistência a Falhas</strong>:
<ul>
<li>Em caso de falha de energia durante a gravação, os dados existentes permanecem intactos, e a operação pode ser retomada na inicialização.</li>
</ul>
</li>
<li><strong>Gerenciamento de Fragmentação</strong>:
<ul>
<li>O mecanismo de compactação reorganiza os dados para liberar espaço, reduzindo a fragmentação.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Exemplo de Compactação Automática</strong></h4>
<p>A NVS realiza automaticamente a compactação quando uma página ativa está cheia. Os dados válidos são movidos para uma nova página, enquanto a antiga é apagada e reinicializada.</p>
<h5><strong>Exemplo de Log Interno</strong></h5>
<pre><code class="language-text">Página Ativa:
+------------+-----------------+-----------------+
| Entrada 1  | Entrada 2       | Entrada 3       |
+------------+-----------------+-----------------+

Página Nova:
+------------+-----------------+-----------------+
| Entrada 2  | Entrada 3       | Entrada 4       |
+------------+-----------------+-----------------+
</code></pre>
<ul>
<li>Entradas apagadas ou inválidas são descartadas durante a movimentação.</li>
</ul>
<hr />
<h4><strong>Diagnóstico com Páginas</strong></h4>
<ol>
<li><strong>Identificação de Páginas Corrompidas</strong>:
<ul>
<li>Utilize logs detalhados (<code>menuconfig -&gt; Enable debug logs</code>) para monitorar a saúde das páginas.</li>
</ul>
</li>
<li><strong>Verificação de Espaço</strong>:
<ul>
<li>Use <code>nvs_get_stats()</code> para verificar o uso de entradas em cada página.</li>
</ul>
</li>
</ol>
<hr />
<h3><strong>Melhores Práticas para Uso da NVS em Produção</strong></h3>
<p>O uso eficiente da NVS (Non-Volatile Storage) no ESP32 é essencial para garantir a longevidade e confiabilidade das aplicações. Abaixo estão as melhores práticas que você pode implementar para aproveitar ao máximo os recursos da NVS, minimizando os problemas de desempenho e desgaste da memória flash.</p>
<hr />
<h4><strong>1. Otimize o Tamanho da Partição NVS</strong></h4>
<ul>
<li>Configure o tamanho da partição NVS com base no volume de dados que será armazenado.</li>
<li>Use a tabela de partições para ajustar o espaço disponível:
<pre><code class="language-csv">nvs,      data, nvs,     0x9000,  0x6000
</code></pre>
<ul>
<li>Neste exemplo, a partição NVS começa no endereço <code>0x9000</code> e possui 24 KB (<code>0x6000</code>).</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>2. Use Namespaces para Organizar os Dados</strong></h4>
<ul>
<li>Divida os dados entre namespaces para evitar conflitos e facilitar o gerenciamento.</li>
<li>Exemplo:
<ul>
<li>Namespace <code>wifi</code> para configurações de rede.</li>
<li>Namespace <code>sensor</code> para dados de sensores.</li>
</ul>
</li>
</ul>
<h5><strong>Benefícios</strong>:</h5>
<ul>
<li>Permite a coexistência de diferentes módulos sem sobrescritas acidentais.</li>
<li>Facilita a depuração e o backup de dados.</li>
</ul>
<hr />
<h4><strong>3. Reduza o Número de Gravações</strong></h4>
<ul>
<li>A memória flash tem um ciclo de vida limitado, geralmente entre 10.000 e 100.000 ciclos de gravação por setor.</li>
<li>Minimize gravações frequentes:
<ul>
<li>Use buffers na RAM para armazenar dados temporários e grave na NVS apenas quando necessário.</li>
<li>Combine múltiplas alterações em uma única operação de gravação.</li>
</ul>
</li>
</ul>
<h5><strong>Exemplo</strong>:</h5>
<p>Grave contadores de eventos somente após atingir um múltiplo de 10:</p>
<pre><code class="language-c">int event_count = 0;

// Incremento em RAM
event_count++;

// Gravação condicional na NVS
if (event_count % 10 == 0) {
    nvs_set_i32(my_handle, "event_count", event_count);
    nvs_commit(my_handle);
}
</code></pre>
<hr />
<h4><strong>4. Monitore o Uso de Memória</strong></h4>
<ul>
<li>Use a função <code>nvs_get_stats()</code> para monitorar a utilização da NVS e identificar fragmentação ou falta de espaço.</li>
<li>Exemplo:</li>
</ul>
<pre><code class="language-c">nvs_stats_t stats;
nvs_get_stats(NULL, &amp;stats);
printf("Usadas: %lu, Livres: %lu, Total: %lu\n",
       stats.used_entries, stats.free_entries, stats.total_entries);
</code></pre>
<hr />
<h4><strong>5. Proteja Dados Sensíveis com Criptografia</strong></h4>
<ul>
<li>Habilite a criptografia da NVS para proteger dados como credenciais e chaves de API.</li>
<li>Configure no <strong>menuconfig</strong>:
<pre><code>Component config -&gt; NVS -&gt; Enable NVS encryption
</code></pre>
</li>
</ul>
<hr />
<h4><strong>6. Trate os Códigos de Erro Adequadamente</strong></h4>
<ul>
<li>Sempre verifique os códigos de retorno das funções da NVS para tratar erros como:
<ul>
<li><code>ESP_ERR_NVS_NOT_FOUND</code>: Chave inexistente.</li>
<li><code>ESP_ERR_NVS_INVALID_HANDLE</code>: Handle inválido.</li>
<li><code>ESP_ERR_NVS_NOT_ENOUGH_SPACE</code>: Falta de espaço.</li>
</ul>
</li>
</ul>
<h5><strong>Exemplo</strong>:</h5>
<pre><code class="language-c">esp_err_t err = nvs_get_i32(my_handle, "key", &amp;value);
if (err == ESP_ERR_NVS_NOT_FOUND) {
    printf("Chave não encontrada.\n");
} else if (err != ESP_OK) {
    printf("Erro ao acessar a NVS: %s\n", esp_err_to_name(err));
}
</code></pre>
<hr />
<h4><strong>7. Execute Backup de Dados Periódicos</strong></h4>
<ul>
<li>Para evitar perda de dados importantes, implemente um mecanismo de backup que exporte os dados da NVS para outro sistema (como um servidor ou cartão SD).</li>
<li>Use um iterador para listar todas as chaves e seus valores:</li>
</ul>
<pre><code class="language-c">nvs_iterator_t it = NULL;
esp_err_t res = nvs_entry_find(NULL, NULL, NVS_TYPE_ANY, &amp;it);
while (res == ESP_OK) {
    nvs_entry_info_t info;
    nvs_entry_info(it, &amp;info);
    printf("Namespace: %s, Chave: %s\n", info.namespace_name, info.key);
    res = nvs_entry_next(&amp;it);
}
nvs_release_iterator(it);
</code></pre>
<hr />
<h4><strong>8. Teste em Condições Reais</strong></h4>
<ul>
<li>Simule falhas de energia e reinicializações durante operações de gravação para garantir que os dados não sejam corrompidos.</li>
<li>Use ferramentas como o monitor serial do ESP-IDF para depuração em tempo real.</li>
</ul>
<hr />
<h4><strong>9. Atualize Regularmente o Firmware</strong></h4>
<ul>
<li>A Espressif constantemente atualiza o ESP-IDF para melhorar a estabilidade da NVS.</li>
<li>Mantenha o ambiente de desenvolvimento atualizado para evitar bugs e aproveitar novos recursos.</li>
</ul>
<hr />
<h4><strong>10. Planeje o Ciclo de Vida do Produto</strong></h4>
<ul>
<li>Se a aplicação grava frequentemente na NVS, considere estratégias para aumentar a durabilidade:
<ul>
<li>Divida os dados em múltiplas partições.</li>
<li>Utilize memórias externas, como FRAM ou EEPROM, para dados de alta frequência.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>Resumo das Melhores Práticas</strong></h4>
<table>
<thead>
<tr>
<th>Prática</th>
<th>Benefício</th>
</tr>
</thead>
<tbody>
<tr>
<td>Otimize o tamanho da partição</td>
<td>Aproveitamento eficiente da memória</td>
</tr>
<tr>
<td>Use namespaces</td>
<td>Organização e isolamento de dados</td>
</tr>
<tr>
<td>Reduza gravações</td>
<td>Aumenta a vida útil da memória flash</td>
</tr>
<tr>
<td>Monitore a memória</td>
<td>Identifica fragmentação e falta de espaço</td>
</tr>
<tr>
<td>Habilite criptografia</td>
<td>Protege dados sensíveis</td>
</tr>
<tr>
<td>Trate erros corretamente</td>
<td>Evita falhas inesperadas</td>
</tr>
<tr>
<td>Faça backups</td>
<td>Garante recuperação de dados</td>
</tr>
<tr>
<td>Teste em condições reais</td>
<td>Valida confiabilidade da aplicação</td>
</tr>
</tbody>
</table>
<hr />
<h3><strong>Exemplos de Aplicações Reais Usando NVS</strong></h3>
<p>A NVS (Non-Volatile Storage) é amplamente utilizada em projetos baseados no ESP32 para armazenamento persistente de dados críticos. Nesta seção, apresentamos exemplos práticos de casos de uso para ilustrar como a NVS pode ser aplicada em cenários reais.</p>
<hr />
<h4><strong>1. Armazenamento de Configurações de Rede</strong></h4>
<p>O ESP32 é frequentemente usado em aplicações IoT que exigem conectividade Wi-Fi. A NVS pode armazenar as credenciais da rede, como SSID e senha, permitindo que o dispositivo se reconecte automaticamente após uma reinicialização.</p>
<h5><strong>Exemplo: Configurações de Wi-Fi</strong></h5>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_wifi.h"

void save_wifi_config(const char *ssid, const char *password) {
    nvs_handle_t handle;
    esp_err_t err = nvs_open("wifi_config", NVS_READWRITE, &amp;handle);
    if (err == ESP_OK) {
        nvs_set_str(handle, "ssid", ssid);
        nvs_set_str(handle, "password", password);
        nvs_commit(handle);
        nvs_close(handle);
        printf("Configurações de Wi-Fi salvas!\n");
    } else {
        printf("Erro ao abrir a NVS para Wi-Fi: %s\n", esp_err_to_name(err));
    }
}

void read_wifi_config(char *ssid, size_t ssid_len, char *password, size_t pass_len) {
    nvs_handle_t handle;
    esp_err_t err = nvs_open("wifi_config", NVS_READONLY, &amp;handle);
    if (err == ESP_OK) {
        nvs_get_str(handle, "ssid", ssid, &amp;ssid_len);
        nvs_get_str(handle, "password", password, &amp;pass_len);
        nvs_close(handle);
        printf("Configurações de Wi-Fi lidas!\n");
    } else {
        printf("Erro ao ler configurações de Wi-Fi: %s\n", esp_err_to_name(err));
    }
}

void app_main(void) {
    nvs_flash_init();

    // Salva configurações de Wi-Fi
    save_wifi_config("MinhaRede", "Senha123");

    // Lê configurações de Wi-Fi
    char ssid[32], password[64];
    read_wifi_config(ssid, sizeof(ssid), password, sizeof(password));

    printf("SSID: %s, Senha: %s\n", ssid, password);
}
</code></pre>
<hr />
<h4><strong>2. Contadores Persistentes</strong></h4>
<p>Em aplicações industriais ou de monitoramento, o ESP32 pode precisar rastrear eventos, como reinicializações ou leituras de sensores. A NVS pode armazenar contadores de forma persistente.</p>
<h5><strong>Exemplo: Contador de Reinicializações</strong></h5>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include "nvs_flash.h"
#include "nvs.h"

void app_main(void) {
    nvs_flash_init();

    nvs_handle_t handle;
    esp_err_t err = nvs_open("system_data", NVS_READWRITE, &amp;handle);
    if (err == ESP_OK) {
        int32_t restart_counter = 0;
        nvs_get_i32(handle, "restart_counter", &amp;restart_counter);
        restart_counter++;
        nvs_set_i32(handle, "restart_counter", restart_counter);
        nvs_commit(handle);
        nvs_close(handle);

        printf("O dispositivo reiniciou %d vezes.\n", restart_counter);
    } else {
        printf("Erro ao acessar a NVS: %s\n", esp_err_to_name(err));
    }
}
</code></pre>
<hr />
<h4><strong>3. Configurações de Sensores</strong></h4>
<p>Sensores conectados ao ESP32 podem exigir calibração ou parâmetros configuráveis, como intervalos de leitura. Esses valores podem ser armazenados na NVS para persistência.</p>
<h5><strong>Exemplo: Configuração de Sensores</strong></h5>
<pre><code class="language-c">typedef struct {
    float offset;
    float scale;
} sensor_config_t;

void save_sensor_config(float offset, float scale) {
    nvs_handle_t handle;
    esp_err_t err = nvs_open("sensor_data", NVS_READWRITE, &amp;handle);
    if (err == ESP_OK) {
        sensor_config_t config = {offset, scale};
        nvs_set_blob(handle, "calibration", &amp;config, sizeof(config));
        nvs_commit(handle);
        nvs_close(handle);
        printf("Configuração do sensor salva!\n");
    } else {
        printf("Erro ao salvar configuração do sensor: %s\n", esp_err_to_name(err));
    }
}

void read_sensor_config(sensor_config_t *config) {
    nvs_handle_t handle;
    esp_err_t err = nvs_open("sensor_data", NVS_READONLY, &amp;handle);
    if (err == ESP_OK) {
        size_t size = sizeof(*config);
        nvs_get_blob(handle, "calibration", config, &amp;size);
        nvs_close(handle);
        printf("Configuração do sensor lida: Offset = %.2f, Escala = %.2f\n",
               config-&gt;offset, config-&gt;scale);
    } else {
        printf("Erro ao ler configuração do sensor: %s\n", esp_err_to_name(err));
    }
}
</code></pre>
<hr />
<h4><strong>4. Gerenciamento de Perfis de Usuário</strong></h4>
<p>Em dispositivos compartilhados, como leitores de cartões ou controladores de acesso, a NVS pode armazenar perfis de usuários com permissões ou configurações específicas.</p>
<hr />
<h4><strong>Práticas Recomendadas para Aplicações Reais</strong></h4>
<ol>
<li><strong>Isolamento Lógico</strong>:
<ul>
<li>Use namespaces para separar os dados de diferentes módulos.</li>
</ul>
</li>
<li><strong>Verificação de Integridade</strong>:
<ul>
<li>Valide os dados lidos da NVS antes de usá-los na aplicação.</li>
</ul>
</li>
<li><strong>Backup e Recuperação</strong>:
<ul>
<li>Implemente mecanismos de backup para evitar perda de dados críticos.</li>
</ul>
</li>
</ol>
<hr />
<h3><strong>FAQ: Respostas a Problemas Comuns com NVS</strong></h3>
<p>Nesta seção, abordamos as dúvidas e problemas mais frequentes relacionados ao uso da NVS no ESP32, fornecendo soluções práticas para cada caso.</p>
<hr />
<h4><strong>1. Por que recebo o erro <code>ESP_ERR_NVS_NOT_FOUND</code> ao tentar ler uma chave?</strong></h4>
<ul>
<li><strong>Causa</strong>: A chave especificada não existe no namespace ou foi apagada.</li>
<li><strong>Solução</strong>:
<ul>
<li>Certifique-se de que a chave foi gravada previamente com <code>nvs_set_*()</code>.</li>
<li>Verifique se o namespace está correto.</li>
<li>Use um valor padrão ao inicializar a variável, como mostrado no exemplo:
<pre><code class="language-c">int32_t value = 0; // Valor padrão
esp_err_t err = nvs_get_i32(my_handle, "key_name", &amp;value);
if (err == ESP_ERR_NVS_NOT_FOUND) {
    printf("Chave não encontrada. Usando valor padrão: %d\n", value);
}
</code></pre>
</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>2. O que fazer quando recebo <code>ESP_ERR_NVS_NOT_ENOUGH_SPACE</code>?</strong></h4>
<ul>
<li><strong>Causa</strong>: Não há espaço suficiente na partição NVS para salvar novos dados.</li>
<li><strong>Solução</strong>:
<ul>
<li>Aumente o tamanho da partição NVS na tabela de partições.</li>
<li>Reduza a quantidade de dados armazenados ou apague chaves antigas:
<pre><code class="language-c">nvs_erase_key(my_handle, "old_key");
nvs_commit(my_handle);
</code></pre>
</li>
<li>Use <code>nvs_get_stats()</code> para monitorar o uso de memória.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>3. Como tratar <code>ESP_ERR_NVS_INVALID_STATE</code> ou dados corrompidos?</strong></h4>
<ul>
<li><strong>Causa</strong>: A NVS está em um estado inválido, possivelmente devido a falhas de energia durante gravações.</li>
<li><strong>Solução</strong>:
<ul>
<li>Apague e reinicialize a partição NVS:
<pre><code class="language-c">esp_err_t err = nvs_flash_erase();
if (err == ESP_OK) {
    nvs_flash_init();
}
</code></pre>
</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>4. É possível alterar o tamanho máximo de uma string ou blob?</strong></h4>
<ul>
<li><strong>Resposta</strong>: Sim, mas há limites físicos impostos pela memória flash:
<ul>
<li>Strings: Até 4000 bytes (incluindo terminador nulo).</li>
<li>Blobs: Até 508 KB ou 97,6% do tamanho da partição.</li>
<li>Certifique-se de que há espaço contíguo suficiente para armazenar os dados.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>5. Como depurar erros inesperados durante operações da NVS?</strong></h4>
<ul>
<li><strong>Solução</strong>:
<ul>
<li>Habilite logs detalhados no <strong>menuconfig</strong>:
<pre><code>Component config -&gt; NVS -&gt; Enable debug logs
</code></pre>
</li>
<li>Use a função <code>esp_err_to_name()</code> para interpretar códigos de erro:
<pre><code class="language-c">esp_err_t err = nvs_set_i32(my_handle, "key", value);
if (err != ESP_OK) {
    printf("Erro: %s\n", esp_err_to_name(err));
}
</code></pre>
</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>6. Por que a leitura de dados falha após uma atualização de firmware?</strong></h4>
<ul>
<li><strong>Causa</strong>: A tabela de partições foi modificada, ou a partição NVS foi sobrescrita durante a atualização.</li>
<li><strong>Solução</strong>:
<ul>
<li>Certifique-se de que a tabela de partições é consistente entre as versões de firmware.</li>
<li>Se necessário, implemente migrações de dados ao atualizar o firmware.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>7. Como lidar com limitações de ciclo de vida da memória flash?</strong></h4>
<ul>
<li><strong>Solução</strong>:
<ul>
<li>Minimize gravações frequentes, combinando alterações em uma única operação.</li>
<li>Para dados de alta frequência, use memórias não voláteis externas, como FRAM ou EEPROM.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>8. Posso compartilhar a NVS entre diferentes dispositivos?</strong></h4>
<ul>
<li><strong>Resposta</strong>: Não diretamente, pois a NVS é projetada para armazenamento local. Para compartilhar dados:
<ul>
<li>Sincronize com um servidor remoto.</li>
<li>Use interfaces de comunicação como Wi-Fi ou Bluetooth.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>9. Existe suporte para dados criptografados na NVS?</strong></h4>
<ul>
<li><strong>Resposta</strong>: Sim, a NVS suporta criptografia nativa no ESP32. Certifique-se de habilitá-la no <strong>menuconfig</strong> e configurar a partição <code>nvs_keys</code>.</li>
</ul>
<hr />
<h4><strong>10. O que acontece se a NVS atingir sua capacidade máxima?</strong></h4>
<ul>
<li><strong>Resposta</strong>:
<ul>
<li>Gravações adicionais falharão com o erro <code>ESP_ERR_NVS_NOT_ENOUGH_SPACE</code>.</li>
<li>Use <code>nvs_erase_key()</code> ou <code>nvs_erase_all()</code> para liberar espaço.</li>
</ul>
</li>
</ul>
<hr />
<h4><strong>11. A NVS é segura contra alterações não autorizadas?</strong></h4>
<ul>
<li><strong>Resposta</strong>: Com a criptografia habilitada, os dados armazenados na NVS estão protegidos contra leitura ou modificação não autorizada. No entanto, ela não é resistente ao apagamento físico dos dados.</li>
</ul>
<hr />
<h4><strong>12. Como restaurar dados padrões em caso de erro crítico?</strong></h4>
<ul>
<li><strong>Solução</strong>:
<ul>
<li>Defina uma lógica para apagar e restaurar dados padrões:
<pre><code class="language-c">esp_err_t err = nvs_flash_erase();
if (err == ESP_OK) {
    nvs_flash_init();
    save_default_values(); // Salva valores padrões
}
</code></pre>
</li>
</ul>
</li>
</ul>
<hr />
<h3><strong>Resumo e Conclusão do Guia sobre NVS</strong></h3>
<p>A Biblioteca de Armazenamento Não Volátil (NVS) é uma ferramenta essencial no desenvolvimento com ESP32, oferecendo uma maneira confiável e eficiente de armazenar dados persistentes. Este guia detalhou os principais conceitos, funcionalidades, melhores práticas e exemplos de uso da NVS, capacitando desenvolvedores a utilizá-la de forma otimizada em suas aplicações.</p>
<hr />
<h4><strong>Recapitulando os Principais Pontos</strong></h4>
<ol>
<li><strong>Introdução à NVS</strong>:
<ul>
<li>A NVS armazena pares de chave-valor em memória flash, com suporte para tipos de dados como inteiros, strings e blobs.</li>
<li>Ideal para armazenar configurações, estados de sensores e contadores persistentes.</li>
</ul>
</li>
<li><strong>Estrutura Interna e Funcionamento</strong>:
<ul>
<li>Baseada em logs e páginas para garantir integridade e minimizar desgaste da memória flash.</li>
<li>Gerencia automaticamente fragmentação e compactação.</li>
</ul>
</li>
<li><strong>Segurança</strong>:
<ul>
<li>Suporte para criptografia nativa protege dados sensíveis contra acesso não autorizado.</li>
</ul>
</li>
<li><strong>Melhores Práticas</strong>:
<ul>
<li>Use namespaces para organizar dados.</li>
<li>Minimize gravações frequentes para prolongar a vida útil da memória.</li>
<li>Monitore o uso de memória com ferramentas como <code>nvs_get_stats()</code>.</li>
</ul>
</li>
<li><strong>Exemplos Reais</strong>:
<ul>
<li>Configurações de rede.</li>
<li>Contadores persistentes.</li>
<li>Dados de calibração de sensores.</li>
</ul>
</li>
<li><strong>Diagnóstico e Soluções de Problemas</strong>:
<ul>
<li>Métodos para identificar e corrigir erros, como <code>ESP_ERR_NVS_NOT_FOUND</code> ou <code>ESP_ERR_NVS_NOT_ENOUGH_SPACE</code>.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Destaques e Benefícios</strong></h4>
<ul>
<li><strong>Persistência Confiável</strong>: Os dados armazenados permanecem intactos mesmo após falhas de energia ou reinicializações.</li>
<li><strong>Flexibilidade</strong>: Suporta diferentes tipos de dados e estruturas, com APIs intuitivas para leitura e gravação.</li>
<li><strong>Robustez</strong>: Projetada para resistir a falhas e minimizar fragmentação.</li>
</ul>
<hr />
<h4><strong>Recomendações Finais</strong></h4>
<ol>
<li><strong>Planeje a Estrutura da NVS</strong>:
<ul>
<li>Determine o tamanho ideal da partição e os namespaces necessários antes de implementar.</li>
</ul>
</li>
<li><strong>Teste em Condições Reais</strong>:
<ul>
<li>Simule cenários como falhas de energia durante gravações para validar a integridade dos dados.</li>
</ul>
</li>
<li><strong>Implemente Rotinas de Backup</strong>:
<ul>
<li>Para dados críticos, considere exportar periodicamente os dados da NVS para um servidor remoto ou dispositivo de armazenamento externo.</li>
</ul>
</li>
<li><strong>Atualize Regularmente o ESP-IDF</strong>:
<ul>
<li>Mantenha o framework atualizado para aproveitar melhorias e correções de bugs relacionados à NVS.</li>
</ul>
</li>
</ol>
<hr />
<h4><strong>Próximos Passos</strong></h4>
<p>Se você deseja explorar mais sobre a NVS ou tecnologias relacionadas ao ESP32, considere:</p>
<ul>
<li><strong>Desenvolver exemplos avançados</strong>: Como integrar a NVS com sistemas de arquivos FAT ou serviços de nuvem.</li>
<li><strong>Aprender sobre outras APIs de armazenamento do ESP-IDF</strong>: Como a SPIFFS ou LittleFS.</li>
<li><strong>Aprofundar-se em segurança embarcada</strong>: Implementar sistemas de proteção de dados completos.</li>
</ul>
<p>Com este guia, você está pronto para utilizar a NVS de forma eficaz em seus projetos com ESP32.</p><p>The post <a href="https://mcu.tec.br/microcontroladores/esp32/esp-idf/introducao-a-biblioteca-de-armazenamento-nao-volatil-nvs-no-esp32-idf/">Introdução à Biblioteca de Armazenamento Não Volátil (NVS) no ESP32-IDF</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">13</post-id>	</item>
	</channel>
</rss>
