ESP32修改BootLoader:在boot中添加GPIO和IIC驱动方式

这篇具有很好参考价值的文章主要介绍了ESP32修改BootLoader:在boot中添加GPIO和IIC驱动方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

ESP32修改BootLoader:在boot中添加GPIO和IIC驱动方式

1. ESP Bootloader简介

ESP32有着强大的引导加载程序(Bootloader)功能:
主要执行以下任务:
内部模块的最小化初始配置;
根据分区表和 ota_data(如果存在)选择需要引导的应用程序(app)分区;
将此应用程序映像加载到 RAM(IRAM 和 DRAM)中,最后把控制权转交给应用程序。
引导加载程序位于 Flash 的 0x1000 偏移地址处。

2. Bootloader修改方式

这里引用C站一个作者的文章,写的不错:点这里
文章分为上下两篇,下篇。

当涉及到用户有特殊BootLoader功能需求时,需要用户自行修改,修改方式主要有:
通过钩子函数。扩展原来的bootloader流程,打个补丁。
通过覆盖bootloader。重写一个bootloader,覆盖原来bootloader的逻辑来运行。
可以发现,这两种方式一个针对小改动需求,一个针对大改动的需要。
怎么添加自己的功能
如果在应用层开发,会做些什么?

嗯,你会在component目录下新建自己功能名的文件夹
之后呢?不知道了… 那就看看component其他组件都放了啥吧。哦,有CMakeLists.txt,component.mk,还有代码目录。那咱们依葫芦画瓢,也放上这些东西。
然后?既然有Cmake的东西,那就看看里面都说了啥。哦,原来里面就是设置好了要编译哪些源文件,头文件目录在哪里,还有配置好编译选项啊,库路径什么的。

是的,这些东西在bootloader里面都有,方法类似。就我的开发方式而言,mycode放在bootloader_support目录下之后,里面的源文件、头文件、库这些的,都跟应用层开发一样。该在CMakeLists.txt加什么就加。
这跟在boot还是在app其实就没啥关系,是CMake这种跨平台编译方式的基本操作。

3. 我的修改方式

本文主要讲解其中一种修改方式:mycode放在bootloader_support目录下之后,里面的源文件、头文件、库这些的,都跟应用层开发一样。该在CMakeLists.txt加什么就加。

下图是本人在bootloader_support文件夹中添加的个人代码“tc2x”
ESP32修改BootLoader:在boot中添加GPIO和IIC驱动方式,ESP开发,嵌入式硬件,驱动开发

并在CmakeLists.txt中添加需要编译的源文件和头文件目录
ESP32修改BootLoader:在boot中添加GPIO和IIC驱动方式,ESP开发,嵌入式硬件,驱动开发

此时,完成了在bootloader_support添加自己的代码。

4. 修改bootloader_utility.c文件

如图,我的boot修改内容主要是基于boot跳转APP失败时,跑一段自己的驱动和应用。
ESP32修改BootLoader:在boot中添加GPIO和IIC驱动方式,ESP开发,嵌入式硬件,驱动开发

5. 在bootloader中实现GPIO控制

实现代码:

#include <string.h>
#include <stdint.h>
#include <limits.h>
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_rom_sys.h"
#include "esp_rom_uart.h"
#include "sdkconfig.h"
#include "esp_rom_crc.h"
#include "esp_rom_gpio.h"
#include "esp_rom_efuse.h"
#include "soc/gpio_periph.h"
#include "soc/soc_caps.h"
#include "hal/gpio_ll.h"
#include "hal/gpio_types.h"

#define CFG_I2C_SCL_PORT   GPIO_PORT_0
#define CFG_I2C_SCL_PIN    18
#define CFG_I2C_SDA_PORT   GPIO_PORT_0
#define CFG_I2C_SDA_PIN    17

#define PIN_OUTPUT_ENABLE(PIN_NAME)               SET_PERI_REG_MASK(PIN_NAME,FUN_IE)
#define PIN_OUTPUT_DISABLE(PIN_NAME)              CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE)
void HAL_GPIO_WritePin(int gpio_port, int gpio_pin, int level)
{
    gpio_ll_set_level(&GPIO, gpio_pin, level);
}
uint8_t HAL_GPIO_ReadPin(int gpio_port, int gpio_pin)
{
    return gpio_ll_get_level(&GPIO, gpio_pin);
}
void HAL_GPIO_SetOut(int gpio_port, int gpio_pin)
{
    esp_rom_gpio_pad_select_gpio(gpio_pin);
    // if (GPIO_PIN_MUX_REG[gpio_pin]) {
    //     PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_pin]);
    //     PIN_SLP_OUTPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_pin]);
    // }
    esp_rom_gpio_pad_pullup_only(gpio_pin);
    gpio_ll_output_enable(&GPIO, gpio_pin);
    //gpio_ll_sleep_output_enable(&GPIO, gpio_pin);
}
void HAL_GPIO_SetIn(int gpio_port, int gpio_pin)
{
    esp_rom_gpio_pad_select_gpio(gpio_pin);
    // if (GPIO_PIN_MUX_REG[gpio_pin]) {
    //     PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_pin]);
    //     PIN_SLP_OUTPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_pin]);
    // }
    esp_rom_gpio_pad_pullup_only(gpio_pin);
    gpio_ll_input_enable(&GPIO, gpio_pin);
   // gpio_ll_sleep_input_enable(&GPIO, gpio_pin);
}

6. 在bootloader中实现IIC控制

代码实现:

void I2C_DELAY(uint32_t us)
{
    esp_rom_delay_us(us);
}
static const char* TAG = "[GPIOIIC]";

#define IIC1 0
#define IIC2 1
#define IICX 0XFF 
#define GPIO_PIN_SET   1 
#define GPIO_PIN_RESET 0  
static int I2C_SCL_PORT = 0;
static int I2C_SCL_PIN  = 18;
static int I2C_SDA_PORT = 0;
static int I2C_SDA_PIN  = 17;
#define us_num 2
#define I2C_READ_BIT                 (0x01)        //!< If this bit is set in the address field, transfer direction is from slave to master.
#define I2C_WRITE_BIT                (0xFE)

static void I2C_SEL(uint8_t I2Cn, uint8_t scl, uint8_t sda)
{
    switch(I2Cn)
    {
    case IIC1:
        I2C_SCL_PORT = CFG_I2C_SCL_PORT;
        I2C_SCL_PIN  = CFG_I2C_SCL_PIN;
        I2C_SDA_PORT = CFG_I2C_SDA_PORT;
        I2C_SDA_PIN  = CFG_I2C_SDA_PIN;
        break;
    case IIC2:
        I2C_SCL_PORT = CFG_I2C_SCL_PORT;
        I2C_SCL_PIN  = CFG_I2C_SCL_PIN;
        I2C_SDA_PORT = CFG_I2C_SDA_PORT;
        I2C_SDA_PIN  = CFG_I2C_SDA_PIN;
        break;
    default: 
        I2C_SCL_PORT = CFG_I2C_SCL_PORT;
        I2C_SCL_PIN  = scl;
        I2C_SDA_PORT = CFG_I2C_SDA_PORT;
        I2C_SDA_PIN  = sda;
        break;
    }
}
static void I2C_SCL_OUTPUT(void)
{
    HAL_GPIO_SetOut(I2C_SCL_PORT, I2C_SCL_PIN);
}
static void I2C_SCL_INPUT(void)
{
    HAL_GPIO_SetIn(I2C_SCL_PORT, I2C_SCL_PIN);
}
static void I2C_SCL_HIGH(void)
{
    HAL_GPIO_WritePin(I2C_SCL_PORT, I2C_SCL_PIN, GPIO_PIN_SET);
}
static void I2C_SCL_LOW(void)
{
    HAL_GPIO_WritePin(I2C_SCL_PORT, I2C_SCL_PIN, GPIO_PIN_RESET);
}
static void I2C_SDA_OUTPUT(void)
{
    HAL_GPIO_SetOut(I2C_SDA_PORT, I2C_SDA_PIN);
}
static void I2C_SDA_INPUT(void)
{
    HAL_GPIO_SetIn(I2C_SDA_PORT, I2C_SDA_PIN);
}
static void I2C_SDA_HIGH(void)
{
    HAL_GPIO_WritePin(I2C_SDA_PORT, I2C_SDA_PIN, GPIO_PIN_SET);
}
static void I2C_SDA_LOW(void)
{
    HAL_GPIO_WritePin(I2C_SDA_PORT, I2C_SDA_PIN, GPIO_PIN_RESET);
}
static uint8_t I2C_SDA_READ(void)
{
    return HAL_GPIO_ReadPin(I2C_SDA_PORT, I2C_SDA_PIN);
}
static uint8_t I2C_SCL_READ(void)
{
    return HAL_GPIO_ReadPin(I2C_SCL_PORT, I2C_SCL_PIN);
}
void I2C_SCL_SDA_TEST(void)
{
    I2C_SCL_OUTPUT();
    I2C_SDA_OUTPUT();
    I2C_SDA_HIGH();
    I2C_SDA_LOW();
}
static void I2C_Init(int scl, int sda)
{
    I2C_SEL(IICX, scl, sda);
    I2C_SCL_INPUT();
    I2C_SDA_INPUT();
    I2C_SCL_OUTPUT();
    I2C_SCL_HIGH();
    I2C_SDA_OUTPUT();
    I2C_SDA_HIGH();
}
static bool i2c_master_clear_bus(void);
static bool i2c_master_issue_startcondition(void);
static bool i2c_master_issue_stopcondition(void);
static bool i2c_master_clock_byte(uint_fast8_t databyte);
static bool i2c_master_clock_byte_in(uint8_t *databyte, bool ack);
static bool i2c_master_wait_while_scl_low(void);
bool gpioi2c_master_init(uint8_t sclpin, uint8_t sdapin)
{
    I2C_Init(sclpin, sdapin);
    return i2c_master_clear_bus();
}
static bool i2c_master_clear_bus(void)
{
    bool bus_clear;
    I2C_SDA_HIGH();
    I2C_SCL_HIGH();
    I2C_DELAY(1);
    if (I2C_SDA_READ() == 1 && I2C_SCL_READ() == 1)
    {
        bus_clear = true;
    }
    else if (I2C_SCL_READ() == 1)
    {
        bus_clear = false;
        ESP_LOGE(TAG, "i2c_master_clear_bus 1 fail");
        for (uint_fast8_t i = 18; i--;)
        {
            I2C_SCL_LOW();
            I2C_DELAY(1);
            I2C_SCL_HIGH();
            I2C_DELAY(1);
            if (I2C_SDA_READ() == 1)
            {
                bus_clear = true;
                break;
            }
        }
    }
    else
    {
        bus_clear = false;
         ESP_LOGE(TAG, "i2c_master_clear_bus 2 fail");
    }
    return bus_clear;
}
static bool i2c_master_issue_startcondition(void)
{
    I2C_SCL_OUTPUT();
    I2C_SDA_OUTPUT();
    I2C_SDA_HIGH();
    I2C_DELAY(1);
    if (!i2c_master_wait_while_scl_low())
    {
        ESP_LOGE(TAG, "i2c_master_wait_while_scl_low fail");
        return false;
    }
    I2C_SDA_LOW();
    I2C_DELAY(1);
    // Other module function expect SCL to be low
    I2C_SCL_LOW();
    I2C_DELAY(1);
    return true;
}
static bool i2c_master_issue_stopcondition(void)
{
    I2C_SDA_LOW();
    I2C_DELAY(1);
    if (!i2c_master_wait_while_scl_low())
    {
        ESP_LOGE(TAG, "i2c_master_issue_stopcondition fail");
        return false;
    }
    I2C_SDA_HIGH();
    I2C_DELAY(1);
    return true;
}
static bool i2c_master_clock_byte(uint_fast8_t databyte)
{
    bool transfer_succeeded = true;
    I2C_SDA_OUTPUT();
    // MSB first
    for (uint_fast8_t i = 0x80; i != 0; i >>= 1)
    {
        I2C_SCL_LOW();
        I2C_DELAY(1);
        if (databyte & i)
        {
            I2C_SDA_HIGH();
        }
        else
        {
            I2C_SDA_LOW();
        }
        if (!i2c_master_wait_while_scl_low())
        {
            ESP_LOGE(TAG, "i2c_master_clock_byte fail");
            transfer_succeeded = false; // Timeout
            break;
        }
    }
    I2C_SCL_LOW();
    I2C_DELAY(1);
    I2C_SDA_INPUT();
    I2C_DELAY(1);
    transfer_succeeded &= i2c_master_wait_while_scl_low();
    transfer_succeeded &= !(I2C_SDA_READ());
    I2C_SCL_LOW();
    I2C_DELAY(1);
    I2C_SDA_OUTPUT();
    return transfer_succeeded;
}
static bool i2c_master_clock_byte_in(uint8_t *databyte, bool ack)
{
    uint_fast8_t byte_read          = 0;
    bool         transfer_succeeded = true;
    I2C_SDA_INPUT();
    for (uint_fast8_t i = 0x80; i != 0; i >>= 1)
    {
        if (!i2c_master_wait_while_scl_low())
        {
            ESP_LOGE(TAG, "i2c_master_clock_byte_in 1 fail");
            transfer_succeeded = false;
            break;
        }
        if (I2C_SDA_READ())
        {
            byte_read |= i;
        }
        else
        {
            // No need to do anything
        }
        I2C_SCL_LOW();
        I2C_DELAY(1);
    }
    I2C_SDA_OUTPUT();
    *databyte = (uint8_t)byte_read;
    if (ack)
    {
        I2C_SDA_LOW();
    }
    else
    {
        I2C_SDA_HIGH();
    }
    I2C_DELAY(1);
    if (!i2c_master_wait_while_scl_low())
    {
        ESP_LOGE(TAG, "i2c_master_clock_byte_in 2 fail");
        transfer_succeeded = false; // Timeout
    }
    I2C_SCL_LOW();
    I2C_DELAY(1);
    return transfer_succeeded;
}
static bool i2c_master_wait_while_scl_low()
{
    uint8_t timeout_counter = 30;
    I2C_SCL_HIGH();
    I2C_DELAY(1);
    while (I2C_SCL_READ() == 0)
    {
        if (timeout_counter-- == 0)
        {
            ESP_LOGE(TAG, "i2c_master_wait_while_scl_low fail");
            return false;
        }
        else
        {
            I2C_DELAY(3);
        }
    }
    return true;
}
bool gpioi2c_master_read(uint8_t address, uint8_t reg_addr, uint8_t * data, uint8_t data_length, bool issue_stop_condition)
{
    bool transfer_succeeded = true;
    transfer_succeeded &= i2c_master_issue_startcondition();
    transfer_succeeded &= i2c_master_clock_byte(address&I2C_WRITE_BIT);
    /** send the address of register which you want to read*/
    transfer_succeeded &= i2c_master_clock_byte(reg_addr);
    /** must send 2 times start condition */
    transfer_succeeded &= i2c_master_issue_startcondition();
    transfer_succeeded &= i2c_master_clock_byte(address|I2C_READ_BIT);
    /* Transfer direction is from Slave to Master */
    while (data_length-- && transfer_succeeded)
    {
        // To indicate to slave that we've finished transferring last data byte
        // we need to NACK the last transfer.
        if (data_length == 0)
        {
            transfer_succeeded &= i2c_master_clock_byte_in(data, (bool)false);
        }
        else
        {
            transfer_succeeded &= i2c_master_clock_byte_in(data, (bool)true);
        }
        data++;
    }
    if (issue_stop_condition || !transfer_succeeded)
    {
        transfer_succeeded &= i2c_master_issue_stopcondition();
    }
    return transfer_succeeded;
}


bool gpioi2c_master_write(uint8_t address, uint8_t reg_addr, uint8_t * data, uint8_t data_length, bool issue_stop_condition)
{
    bool transfer_succeeded = true;
    
    transfer_succeeded &= i2c_master_issue_startcondition();
ESP_LOGD(TAG, "gpioi2c_master_write transfer_succeeded1=%d",transfer_succeeded);
    transfer_succeeded &= i2c_master_clock_byte(address&I2C_WRITE_BIT);
ESP_LOGD(TAG, "gpioi2c_master_write transfer_succeeded2=%d",transfer_succeeded);
    /** send the address of register which you want to write */
    transfer_succeeded &= i2c_master_clock_byte(reg_addr);
ESP_LOGD(TAG, "gpioi2c_master_write transfer_succeeded3=%d",transfer_succeeded);
    /* Transfer direction is from Master to Slave */
    while (data_length-- && transfer_succeeded)
    {
        transfer_succeeded &= i2c_master_clock_byte(*data);
        data++;
    }
    if (issue_stop_condition || !transfer_succeeded)
    {
        transfer_succeeded &= i2c_master_issue_stopcondition();
ESP_LOGD(TAG, "gpioi2c_master_write transfer_succeeded4=%d",transfer_succeeded);
    }
    return transfer_succeeded;
}

7. 总结

通过以上方式,可以实现在esp32修改BootLoader代码,并实现GPIO和IIC驱动,从而实现自己的修改需求。文章来源地址https://www.toymoban.com/news/detail-724612.html

到了这里,关于ESP32修改BootLoader:在boot中添加GPIO和IIC驱动方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ESP32 IDF iic通信( 已验证) C语言

    关于iic原理建议B站自己看视频去, 然后本文主要实现了esp32的初始化, 写地址, 写数据, 读数据的功能, 从机的代码因为展示不需要,没写. 园子里面有个兄弟写了iic的代码.但是里面有点毒,多发了次地址验证,所以才有这篇文章; 代码注释比较多, 愿君少走弯路❀ 以下是头文件主要

    2024年02月03日
    浏览(40)
  • ESP32 CAM GPIO引脚定义

    官方文档 ESP32-CAM摄像头开发板 | 安信可科技    注意: 1.请保证模块输入电源至少5V 2A,否则图片会有几率出现水纹。 2.ESP32 GPIO32管脚控制摄像头电源,当摄像头工作时,请把GPIO32拉低。 3.由于IO0连接摄像头XCLK,使用时请把IO0悬空,请勿接高低电平。 4. 出厂已含有默认固件,不

    2024年02月16日
    浏览(38)
  • ESP32开发(二)——GPIO管脚配置

            在VSCode中搭建完ESP32的开发环境后,就可以开始快乐编程了。在进行ESP32开发前,我们需要对它的API有个基本了解。 一.资料下载          授人以鱼不如授人以渔,学会找学习资料很重要。在乐鑫的官网上,给出了各种型号的技术支持,点击支持,技术文档。    

    2024年02月10日
    浏览(34)
  • stm32-iic 时序驱动

    数据发送

    2024年02月12日
    浏览(34)
  • ESP32-硬件IIC读取温湿度传感器SHT30

    esp32 使用硬件I2C读取温湿度传感器SHT30,例程基于 EDP-IDF-4.4.X 的I2C Simple Example 例程修改 打开 VSCODE ,通过 查看-- 命令面板(快捷键Ctrl+Shift+P),打开 ESP-IDF 的例程后,选择 i2c_simple 例程,点击 Create project using example i2c_simple,选择自己要存储的目录。【PS:工程的目录不要有中文路

    2024年02月02日
    浏览(39)
  • 一起玩儿物联网人工智能小车(ESP32)——15. 用ESP32的GPIO控制智能小车运动起来(三)

    摘要:本文介绍用ESP32的GPIO控制智能小车朝各个方向运动 在前面已经实现了用ESP32开发板控制单个车轮正反向旋转。接下来就是同时控制4个轮子转动,让整个智能小车动起来了。 说干就干,第一步还是初始化8个GPIO引脚,将这8个引脚的初始状态都设置为低电平。配置好了以

    2024年01月23日
    浏览(53)
  • 一起玩儿物联网人工智能小车(ESP32)——14. 用ESP32的GPIO控制智能小车运动起来(二)

    摘要:本文主要讲解如何使用Mixly实现对单一车轮的运动控制。 下面就该用程序控制我们的小车轮子转起来了。打开Mixly软件,然后单击顶部“文件”菜单中的“新建”功能,我们来开启一个新程序的开发工作。 我们的工作同样是先从最简单的开始,初期只控制一个轮子,实

    2024年02月04日
    浏览(50)
  • 一起玩儿物联网人工智能小车(ESP32)——13. 用ESP32的GPIO控制智能小车运动起来(一)

    摘要:本文更深入的讲述了GPIO的相关知识,并完成了导线连接工作,为下一步的软件开发做好了准备。 通用输入输出端口(GPIO:General Purpose Input/Output Port),在前面已经有了初步的介绍,本篇将进行更详细的阐述,希望大家能够了解GPIO端口是如何工作的。 通用输入输出端

    2024年02月04日
    浏览(42)
  • STM32驱动OLED显示汉字,字符------IIC

    目录 一、OLED简介 二、IIC简介 三、代码介绍 四、完整代码 OLED,即有机发光二极管( Organic Light Emitting Diode )。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下

    2023年04月11日
    浏览(48)
  • STM32(HAL库)软件IIC驱动OLED

    目录 1、简介 2、CubeMX初始化配置 2.1 基础配置 2.1.1 SYS配置  2.1.2 RCC配置 2.2 软件IIC引脚配置 2.3 项目生成  3、KEIL端程序整合 3.1 OLED驱动添加 3.3 主函数代 3.4 效果展示 本文通过STM32F103C8T6单片机(HAL库)通过软件IIC方式对OLED进行驱动。 2.1.1 SYS配置  2.1.2 RCC配置 首先在建立Ha

    2024年02月14日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包