ESP8266 RTOS SDK开发


ESP8266 RTOS SDK开发


源码RTOS SDK包的下载和编译

SDK 版本: 18c3a1944ac3b1454a87e578705cd90026525608

git clone https://gitee.com/xuhongv/ESP8266_RTOS_SDK.git

修改.gitmodules文件
[submodule "components/json/cJSON"]
        path = components/json/cJSON
        url = https://gitee.com/xuhongv/cJSON.git
[submodule "components/mbedtls/mbedtls"]
        path = components/mbedtls/mbedtls
        url = https://gitee.com/xuhongv/mbedtls.git
[submodule "components/lwip/lwip"]
        path = components/lwip/lwip
        url = https://gitee.com/xuhongv/esp-lwip.git
[submodule "components/mqtt/esp-mqtt"]
        path = components/mqtt/esp-mqtt
        url = https://gitee.com/xuhongv/esp-mqtt.git
[submodule "components/coap/libcoap"]
        path = components/coap/libcoap
        url = https://gitee.com/xuhongv/libcoap.git
更新子模块
git submodule update --init --recursive

添加环境变量

export IDF_PATH=~/Esp/ESP8266_RTOS_SDK
export ~/Esp/Toolchain/xtensa-lx106-elf/bin
python -m pip install --user -r /home/mo/Esp/ESP8266_RTOS_SDK/requirements.txt

固件烧录

1.管脚定义

模式 CH_PD(EN) RST GPIO15 GPIO0 GPIO2 TXD0
下载模式
运行模式
测试模式 - - -

注:GPIO6~GPIO11被用于连接开发板的闪存(Flash Memory)因此建议不要使用GPIO6~GPIO11。请谨慎使用GPIO10,请勿使用GPIO9。(IO2 log调试默认波特率74880)

内存分布

ESP8266 的内存分布涉及不同类型的存储区域,包括指令 RAM(IRAM)、数据 RAM(DRAM)、闪存和 RTC 内存。

在ESP8266_RTOS_SDK中的esp8266.ld中:

MEMORY
{
  /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
  of the various regions. */

  /* IRAM for cpu. The length is due to the cache mode which is able to be set half or full mode. */
  iram0_0_seg (RX) :                 org = 0x40100000, len = CONFIG_SOC_IRAM_SIZE

  /* Even though the segment name is iram, it is actually mapped to flash and mapped constant data */
  iram0_2_seg (RX) :                 org = 0x40200010 + (APP_OFFSET & (0x100000 - 1)),
                                     len = APP_SIZE - 0x10

  /*
    (0x18 offset above is a convenience for the app binary image generation. The .bin file which is flashed
    to the chip has a 0x10 byte file header. Setting this offset makes it simple to meet the flash cache.)
  */


  /* Length of this section is 96KB */
  dram0_0_seg (RW) :                 org = 0x3FFE8000, len = 0x18000

  /* (See iram0_2_seg for meaning of 0x10 offset in the above.) */

  /* RTC memory. Persists over deep sleep */
  rtc_data_seg(RW) :                 org = 0x60001200, len = 0x200
}

内存映射示意图

0x3F400000 |---------------------------|
           |       DROM (Data ROM)     |
           |---------------------------|
0x3FFE8000 |---------------------------|
           |       DRAM (Data RAM)     |
           |---------------------------|
0x40100000 |---------------------------|
           |   IRAM (Instruction RAM)  |
           |---------------------------|
0x40200000 |---------------------------|
           |IROM(Flash Instruction ROM)|
           |---------------------------|
0x60001200 |---------------------------|
           |       RTC RAM             |
           |---------------------------|

  • IRAM (iram0_0_seg 和 iram0_2_seg): 用于存储指令和常量数据。地址和长度配置是为了适应缓存模式的设置。
  • DRAM (dram0_0_seg): 用于存储动态数据,包括全局变量和堆栈数据。该段内存的配置固定为 96KB。
  • RTC 内存 (rtc_data_seg): 用于存储需要在深度睡眠模式下保留的数据,通常用于保存系统状态或关键数据。

典型的内存分布示例:

0x3FFE8000: .data, .bss
0x3FFF0000: .heap_start
0x3FFF8000: .heap_end (动态分配区)
0x40100000: .text (IRAM 中的代码)
0x40200000: .irom0.text (从闪存中映射的代码)

如何查看内存分布

ESP8266 SDK 提供了一些工具和函数来查看内存的使用情况:

  • heap_caps_get_free_size():获取可用的堆大小。
  • heap_caps_get_largest_free_block():获取最大的连续可用堆块大小。
  • system_get_free_heap_size():获取剩余的堆大小。

修改内存分配

可通过修改链接脚本esp8266.project.ld.in来调整内存分配。

  • 找到/ESP8266_RTOS_SDK/components/esp8266/ld/esp8266.project.ld.in
  • 调整 _bss_end 的地址来改变堆的大小。例如,将 _bss_end 向后移动以增加堆大小。
.dram0.bss (NOLOAD) :
{
    . = ALIGN (8);
    _bss_start = ABSOLUTE(.);

    mapping[dram0_bss]

    *(.dynsbss)
    *(.sbss)
    *(.sbss.*)
    *(.gnu.linkonce.sb.*)
    *(.scommon)
    *(.sbss2)
    *(.sbss2.*)
    *(.gnu.linkonce.sb2.*)
    *(.dynbss)
    *(.share.mem)
    *(.gnu.linkonce.b.*)

    . = ALIGN (8);
    _bss_end = ABSOLUTE(. + 0x1000);  /* 增加 0x1000 大小的堆 */
} > dram0_0_seg

注意,这里 0x1000 是增加的堆大小,你可以根据需要调整这个值。

程序例程

1.PWM设置

频率范围:100Hz ~ 1kHz


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"

#include "esp_log.h"
#include "esp_system.h"
#include "esp_err.h"

#include "esp8266/gpio_register.h"
#include "esp8266/pin_mux_register.h"

#include "driver/pwm.h"

#define PWM_0_OUT_IO_NUM 15

static const char *TAG = "main";

// pwm pin number
const uint32_t pin_num[1] = {PWM_0_OUT_IO_NUM};

// phase table, delay = (phase[x]/360)*PERIOD
float phase[1] = {0};

void buzzer_freq_set(uint32_t freq)
{
    uint32_t period = 1000000 / freq;
    uint32_t duty   = period / 2;

    pwm_set_period(period);
    pwm_set_duty(0, duty);
    pwm_start();
}

void app_main()
{
    uint32_t pwm_period = 1000;    // 1kHz
    uint32_t pwm_duty   = 500;

    ESP_LOGI(TAG, "M.Y.Dodo\n");
    pwm_init(pwm_period, &pwm_duty, 1, pin_num);
    // pwm_set_phases(phase);
    pwm_start();

    uint32_t freq = 100;
    buzzer_freq_set(freq);

    int16_t count = 0;

    while (1) {
        count++;
        if (count == 3) {
            count = 0;
            freq += 100;
            buzzer_freq_set(freq);
        }

        vTaskDelay(1000 / portTICK_RATE_MS);
    }
}

连接MQTT

强制门户认证

强制门户:它的原理是DNS劫持,在手机等设备连接热点后,会尝试去请求DNS服务器获取一些网址的IP地址,此时wifi设备端就可以监听请求包,然后将自己的IP地址作为DNS解析结果返回给连接设备。
DNS采用UDP协议,端口号是53。
连接wifi后,手机自动弹出一个网页,跳转wifi配网页面。

注意

连接 Wi-Fi 时扫描AP会失败

如果 Wi-Fi 正在连接,则调用函数 esp_wifi_scan_start() 后扫描将立即失败,因为 Wi-Fi 连接优先级高于扫描。如果扫描是因为 Wi-Fi 连接而失败的,此时推荐采取的策略为:等待一段时间后重试。因为一旦 Wi-Fi 连接完成后,扫描将立即成功。

错误处理

Guru Meditation Error报错定位分析


打印了异常时,PC、PS等各个寄存器的值,其中Backtrace打印了可能异常的地方,可以根据这个定位到具体对应的代码。
在终端输入

xtensa-lx106-elf-addr2line -pfiaC -e build/PROJECT_NAME.elf ADDRESS  0x4022b560:0x3fff2390 0x4022b5e0:0x3fff23b0 0x40226ff1:0x3fff23c0 0x40226f41:0x3fff23d0 0x402234b1:0x3fff23e0 0x40223511:0x3fff23f0 0x40224420:0x3fff2440 0x402248e9:0x3fff24e0 0x4023fb8a:0x3fff2530 0x4027d095:0x3fff2540 0x4023f758:0x3fff2560 0x4023f827:0x3fff25a0

使用 cJSON_PrintUnformatted函数时始终返回NULL

原因:由于 'nano' 版本是简化版,某些复杂的格式化功能可能会受到限制。

解决方法:make menuconfig > Component config > Newlib > [ ] Enable 'nano' formatting options for printf/scanf family 取消此项选择

官方教程

posted @ 2021-06-27 22:03  D·Kingson.Mo  阅读(585)  评论(0)    收藏  举报