BUG——GT911上电后中断一直触发

news2024/9/24 13:17:46

版型:正点原子 I.MX6UL  MINI板 

屏幕:7寸 1024*600  ATK-MD0700R V1.4

     我的建议是买7寸屏幕就不要Mini板,因为Mini板太小装不下7寸屏幕,你需要一个更大的板子

   简介:

     算是作为一个后来者对这一现象的补充。解决方案就是在中断开启前主动清零,详情可见本篇末尾。

        具体情形是,上电之后,本应不会触发中断,结果却一直疯跳,14s左右进入1400多次中断,与扫描频率100Hz相近。

 启发:

         看了一些博客,说0x814E这个寄存器没有清零,实际上是有清零这一步的。在测试中发现,上电后虽然中断会一直触发,但只要你在屏幕上乱摸一会儿,就可以正常了。不过这显然不是什么正经的解决方案。

void GT911_read_tpcoord(void)
{
    uint8_t buf[4];
    uint8_t regvalue = 0;

    regvalue = GT911_read_byte(GT911_ADDR, GT_GSTID_REG);
    GT911_write_byte(GT911_ADDR, GT_GSTID_REG, 0x00);/*清零*/
    GT911_dev.point_num = regvalue & 0XF; /* 计算读取了多少个点 */

    /* 读取当前所有的触摸坐标值 */
    for (uint8_t i = 0; i < GT911_dev.point_num; ++i)
    {
        GT911_read_len(GT911_ADDR, GT911_TPX_TBL[i], 4, buf); /* 读取坐标值 */
        GT911_dev.x[i] = ((u16)buf[1] << 8) + buf[0];
        GT911_dev.y[i] = (((u16)buf[3] << 8) + buf[2]);
    }
}



volatile static uint32_t count = 0;
void GT911_irqhandler(void)
{
 gpio_clearintflags(GPIO1, 9); /* 清除中断标志位 */
 if (GT911_dev.initfalg == GT911_INIT_FINISHED)
  {
   GT911_dev.intflag = 1;
   GT911_read_tpcoord();
   printf("%d\r\n", GT911_dev.point_num);
   for (uint8_t i = 0; i < GT911_dev.point_num; ++i)
   {
    printf("X%d:%d  Y%d: %d\r\n", i, GT911_dev.x[i], i, GT911_dev.y[i]);
   }
   printf("\r\n");
  }
 printf("Interrupt:%d---------------------\r\n", ++count);
}

 尝试:

        看情形,觉得是清零不到位,于是在中断前面加了一个清零步骤,就有了双倍清零效果

volatile static uint32_t count = 0;
void GT911_irqhandler(void)
{
 gpio_clearintflags(GPIO1, 9); /* 清除中断标志位 */
 GT911_write_byte(GT911_ADDR, GT_GSTID_REG, 0x00);/*清零*/

 if (GT911_dev.initfalg == GT911_INIT_FINISHED)
  {
   GT911_dev.intflag = 1;
   GT911_read_tpcoord();
   printf("%d\r\n", GT911_dev.point_num);
   for (uint8_t i = 0; i < GT911_dev.point_num; ++i)
   {
    printf("X%d:%d  Y%d: %d\r\n", i, GT911_dev.x[i], i, GT911_dev.y[i]);
   }
   printf("\r\n");
  }
 printf("Interrupt:%d---------------------\r\n", ++count);
}

        结果居然真的停了,重启过几次,发现都是11次,没有变。

    为此,我就在结构体里面多添加了一个成员,专门用于清零计数。中断里面添加了个分支,用于判断是否清零了11次(不同的芯片、板子可能不同)。虽然可行,但终究多了一步,感觉有些浪费

struct GT911_dev_struct
{
    uint16_t x[5];     /* X轴坐标 	*/
    uint16_t y[5];     /* Y轴坐标 	*/
    uint8_t initfalg;  /* 触摸屏初始化状态 */
    uint8_t intflag;   /* 标记中断有没有发生 */
    uint8_t point_num; /* 触摸点 		*/
    uint8_t init_clear;
};






/*--------------------中断处理函数---------------------------/


void GT911_irqhandler(void)
{
    if (GT911_dev.init_clear < 12)
    {
        GT911_write_byte(GT911_ADDR, GT_GSTID_REG, 0x00);
        ++GT911_dev.init_clear;
    }
    else
    {
        if (GT911_dev.initfalg == GT911_INIT_FINISHED)
        {
            GT911_dev.intflag = 1;
            GT911_read_tpcoord();
            printf("%d\r\n", GT911_dev.point_num);
            for (uint8_t i = 0; i < GT911_dev.point_num; ++i)
            {
                printf("X%d:%d  Y%d: %d\r\n", i, GT911_dev.x[i], i, GT911_dev.y[i]);
            }
            printf("\r\n");
        }
    }

    gpio_clearintflags(GPIO1, 9); /* 清除中断标志位 */
    printf("Interrupt:%d---------------------\r\n", ++count);
}

         于是就想着,在GT911中断开启之后,板子中断开启之前对芯片清零,于是初始化代码变成了

    delay_ms(10);
    GT911_write_byte(GT911_ADDR, GT911_Command_Reg, 0);


/*----------------中断前清零--------------------*/
    for (uint16_t i = 0; i < 15; i++)
    {
        GT911_write_byte(GT911_ADDR, GT_GSTID_REG, 0x00);
        printf("Clear:%d---------------------\r\n", i);
    }
/*----------------中断前清零--------------------*/


    GIC_EnableIRQ(GPIO1_Combined_0_15_IRQn);                                                                                   /* 使能GIC中对应的中断 */
    system_register_irqhandler(GPIO1_Combined_0_15_IRQn, (system_irq_handler_t)GT911_irqhandler, NULL); /* 注册中断服务函数 */ // 放在前面,不然
    gpio_enableint(GPIO1, 9);
    delay_ms(100);
    GT911_dev.initfalg = GT911_INIT_FINISHED;
done:
    delay_ms(10);

         结果没什么效果,不过转念一想中断里面是双倍清零,问题可能就出在了这里

 于是发生了下面这一幕,虽然有效,但又不完全有。

 

         本着闲着也是闲着,后面就测试了多种情况

/*----------------中断前清零--------------------*/
    for (uint16_t i = 0; i < 15; i++)
    {
        GT911_write_byte(GT911_ADDR, GT_GSTID_REG, 0x00);
        printf("Clear:%d---------------------\r\n", i);
    }
/*----------------中断前清零--------------------*/

 :把for循环里的printf去掉

        清零足足600次,才能清掉

:添加延时

        延时1ms,清零80次左右,可以正常清掉。进一步测试发现,延时越长所需清零次数越少。不过延时越少也意味着所耗费的时间越长,延时10ms与在中断里面清零的效果差不多,再往上20ms、50ms差距就不大了,都能在10次以内清零。50ms与100ms效果相同,达到500ms效果反而差了些,后面就没继续测了。

总结:

         中断开启前,以10ms左右的延时清零8次左右即可解决问题,当然具体情况具体讨论,在这个参考上调整一下。

    for (uint16_t i = 0; i < 8; i++)
    {
        delay_ms(10);
        GT911_write_byte(GT911_ADDR, GT_GSTID_REG, 0x00);
    }

        源码在下面,都是在正点原子代码的基础上微调一下

 Touch.h源码

#ifndef __BSP_TOUCH_H
#define __BSP_TOUCH_H
#include "imx6ul.h"
/* 触摸屏结构体 */
struct GT911_dev_struct
{
    uint16_t x[5];     /* X轴坐标 	*/
    uint16_t y[5];     /* Y轴坐标 	*/
    uint8_t initfalg;  /* 触摸屏初始化状态 */
    uint8_t intflag;   /* 标记中断有没有发生 */
    uint8_t point_num; /* 触摸点 		*/
    uint8_t init_clear;
};

extern struct GT911_dev_struct GT911_dev;

void touch_init(void);
void GT911_read_tpcoord(void);

#endif // !__BSP_TOUCH_H

Touch.c源码

#include "bsp_touch.h"
#include "bsp_gpio.h"
#include "delay.h"
#include "bsp_i2c.h"
#include "myDebug.h"
#include "bsp_int.h"

#define GT911_ADDR 0x28 // 0xBA

/*GT911寄存器*/
// W
// 0:读坐标状态 1:差值原始值 2:软件复位3:基准更新(内部测试) 4:基准校准(内部测试) 5 : 关屏其余值无效
#define GT911_Command_Reg 0x8040

// R/W
#define GT911_Config_Version_Reg 0x8047
#define GT911_XL_Reg 0x8048
#define GT911_YL_Reg 0x8049
#define GT911_YH_Reg 0x804A
#define GT911_Touch_Number_Reg 0x804C
#define GT911_Module_Switch1_Reg 0x804D
#define GT911_Module_Switch2_Reg 0x804E
#define GT911_Shake_Count_Reg 0x804F // 手指按下/松开去抖次数
#define GT911_Filter_Reg 0x8050
#define GT911_Large_Touch_Reg 0x8051
#define GT911_Noise_Reduction_Reg 0x8052 // 噪声消除值(系数为 1,0-15 有效)

#define GT911_Screen_Touch_Level_Reg 0x8053 // bit 7-0 屏上触摸点从无到有的阈值
#define GT911_Screen_Leave_Level_Reg 0x8054 // bit 7-0 屏上触摸点从有到无的阈值
#define GT911_Low_Power_Control_Reg 0x8055  // bit 3-0 进低功耗时间(0~15s)

#define GT_PID_REG 0x8140
#define GT911_ID1_Reg 0x8140
#define GT911_ID2_Reg 0x8141
#define GT911_ID3_Reg 0x8142
#define GT911_ID4_Reg 0x8143

#define GT_GSTID_REG 0X814E /* GT911当前检测到的触摸情况 */
#define GT_TP1_REG 0X8150   /* 第一个触摸点数据地址 */
#define GT_TP2_REG 0X8158   /* 第二个触摸点数据地址 */
#define GT_TP3_REG 0X8160   /* 第三个触摸点数据地址 */
#define GT_TP4_REG 0X8168   /* 第四个触摸点数据地址  */
#define GT_TP5_REG 0X8170   /* 第五个触摸点数据地址   */

#define GT911_XYCOORDREG_NUM 30  /* 触摸点坐标寄存器数量 */
#define GT911_INIT_FINISHED 1    /* 触摸屏初始化完成 			*/
#define GT911_INIT_NOTFINISHED 0 /* 触摸屏初始化未完成 			*/

// GT911模块开关寄存器
// bit 5-4  Stretch_rank
// bit 3    X2Y(X,Y坐标交换)

// bit 1-0 INT输出极性选择
#define GT911_Module_Switch1_INT_RisingEdge 0x00
#define GT911_Module_Switch1_INT_FallingEdge 0x01
#define GT911_Module_Switch1_INT_LowLevel 0x02
#define GT911_Module_Switch1_INT_HighLevel 0x03

void GT911_irqhandler(void);
uint8_t GT911_read_byte(uint8_t addr, uint32_t reg);
uint8_t GT911_write_byte(uint8_t addr, uint32_t reg, uint8_t data);
void GT911_write_len(uint8_t addr, uint32_t reg, uint32_t len, uint8_t *buf);
void GT911_read_len(uint8_t addr, uint32_t reg, uint32_t len, uint8_t *buf);

/*变量定义*/
struct GT911_dev_struct GT911_dev;

/*触摸屏初始化*/
void touch_init(void)
{
    IOMUXC_InitTypeDef iomuxc_init = {0};
    iomuxc_init.SPEED = IOMUXC_SPEED_MEDIUM;
    iomuxc_init.SRE = IOMUXC_SRE_Fast_Slew_Rate;
    iomuxc_init.DSE = IOMUXC_DSE_R0_6;
    iomuxc_init.HYS = IOMUXC_HYS_Enable;
    iomuxc_init.SION = IOMUXC_SION_Disable;

    IOMUXC_InitPin(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09, &iomuxc_init); // CT_RST
    IOMUXC_InitPin(IOMUXC_GPIO1_IO09_GPIO1_IO09, &iomuxc_init);        // CT_INT

    iomuxc_init.PULL = IOMUXC_PULL_PUS_47K_UP | IOMUXC_PULL_PKE_Keeper_Enable | IOMUXC_PULL_PUE_Pull;
    iomuxc_init.HYS = IOMUXC_HYS_Disable;
    iomuxc_init.SION = IOMUXC_SION_Enable;
    IOMUXC_InitPin(IOMUXC_UART5_TX_DATA_I2C2_SCL, &iomuxc_init);
    IOMUXC_InitPin(IOMUXC_UART5_RX_DATA_I2C2_SDA, &iomuxc_init);

    GPIO_InitTypeDef gpio_init = {0};
    gpio_init.Pin = GPIO_PIN_9;
    gpio_init.Direction = GPIO_DIR_Output;
    gpio_init.Output = GPIO_OUTPUT_High;
    // CT_INT
    GPIO_Init(GPIO1, &gpio_init);
    // CT_RST
    GPIO_Init(GPIO5, &gpio_init);

    i2c_init(I2C2);

    // 0xBA设备地址的复位
    // GPIO_ClearPin(GPIO5, GPIO_PIN_9);
    // GPIO_ClearPin(GPIO1, GPIO_PIN_9);
    // delay_ms(10);                   // 大于100us即可
    // GPIO_SetPin(GPIO5, GPIO_PIN_9); // 停止复位
    // delay_ms(100);                  // 大于5ms即可
    GPIO_ClearPin(GPIO5, GPIO_PIN_9);
    delay_ms(10);
    GPIO_SetPin(GPIO5, GPIO_PIN_9); // 停止复位
    delay_ms(10);
    GPIO_ClearPin(GPIO1, GPIO_PIN_9); /* 拉低INT引脚 */
    delay_ms(100);

    /***********GT911内部配置初始化**************/
    GT911_dev.initfalg = GT911_INIT_NOTFINISHED;
    GT911_dev.point_num = 0;
    GT911_dev.init_clear = 0;
    for (uint8_t i = 0; i < 5; ++i)
    { /* 避免编译器自动赋值 */
        GT911_dev.x[i] = 0;
        GT911_dev.y[i] = 0;
    }

    volatile uint8_t temp[7];                                   // 一不留神就被编译器优化死了
    GT911_read_len(GT911_ADDR, GT_PID_REG, 6, (uint8_t *)temp); /* 读取产品ID */
    temp[6] = temp[4];
    temp[4] = 0;
    printf("CTP ID:%s\r\n", temp);                             /* 打印ID */
    printf("Default Ver:%#x\r\n", ((temp[5] << 8) | temp[6])); /* 打印固件版本 */

    /* 重新设置中断IO,配置为中断功能 */
    IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO09_GPIO1_IO09, 0x0080);
    gpio_init.Direction = GPIO_DIR_Input;
    gpio_init.InterruptMode = GPIO_INT_RisingEdge;
    gpio_init.Output = GPIO_OUTPUT_Low;

    if (temp[0] != 0x31)
    {
        temp[0] = GT911_read_byte(GT911_ADDR, 0x804D) & 0x3; /* 获取中断模式 */
        printf("9xx\r\n");
    }
    else
    {
        temp[0] = GT911_read_byte(GT911_ADDR, 0x8056) & 0x3;
    }

    switch (temp[0])
    {
    case 0x0:
        printf("InterruptMode:IntRisingEdge\r\n");
        gpio_init.InterruptMode = GPIO_INT_RisingEdge;
        break;
    case 0x1:
        printf("InterruptMode:IntFallingEdge\r\n");
        gpio_init.InterruptMode = GPIO_INT_FallingEdge;
        break;
    case 0x2:
        printf("InterruptMode:IntLowLevel\r\n");
        gpio_init.InterruptMode = GPIO_INT_Low;
        break;
    case 0x3:
        printf("InterruptMode:IntHighLevel\r\n");
        gpio_init.InterruptMode = GPIO_INT_High;
        break;
    default:
        printf("InterruptMode: Error\r\n");
        gpio_init.InterruptMode = GPIO_INT_BothEdge;
        break;
    }

    GPIO_Init(GPIO1, &gpio_init);
    if (GT911_write_byte(GT911_ADDR, GT911_Command_Reg, 0x2))
    {
        GT911_dev.initfalg = GT911_INIT_NOTFINISHED;
        goto done;
    }

    delay_ms(10);
    GT911_write_byte(GT911_ADDR, GT911_Command_Reg, 0);

    for (uint16_t i = 0; i < 8; i++)
    {
        delay_ms(10);
        GT911_write_byte(GT911_ADDR, GT_GSTID_REG, 0x00);

        // printf("Clear:%d---------------------\r\n", i);
    }
    GIC_EnableIRQ(GPIO1_Combined_0_15_IRQn);                                                                                   /* 使能GIC中对应的中断 */
    system_register_irqhandler(GPIO1_Combined_0_15_IRQn, (system_irq_handler_t)GT911_irqhandler, NULL); /* 注册中断服务函数 */ // 放在前面,不然
    gpio_enableint(GPIO1, 9);
    delay_ms(100);
    GT911_dev.initfalg = GT911_INIT_FINISHED;
done:
    delay_ms(10);
}

/*
 * @description			: GPIO1_IO9最终的中断处理函数
 * @param				: 无
 * @return 				: 无
 */
volatile static uint32_t count = 0;
void GT911_irqhandler(void)
{
    gpio_clearintflags(GPIO1, 9); /* 清除中断标志位 */
    // printf("Interrupt:%d---------------------\r\n", ++count);
    if (GT911_dev.init_state == GT911_INIT_FINISHED)
    {
        GT911_read_tpcoord();
        if (GT911_dev.point_num)
            GT911_dev.int_flag = 1;
        // printf("%d\r\n", GT911_dev.point_num);
        // for (uint8_t i = 0; i < GT911_dev.point_num; ++i)
        // {
        //     printf("X%d:%d  Y%d: %d\r\n", i, GT911_dev.x[i], i, GT911_dev.y[i]);
        // }
        // printf("\r\n");
    }
}

/*
 * @description	: 向GT911写入数据
 * @param - addr: 设备地址
 * @param - reg : 要写入的寄存器
 * @param - data: 要写入的数据
 * @return 		: 操作结果
 */
uint8_t GT911_write_byte(uint8_t addr, uint32_t reg, uint8_t data)
{
    uint8_t status = 0;
    uint8_t writedata = data;
    struct i2c_transfer masterXfer;

    /* 配置I2C xfer结构体 */
    masterXfer.slaveAddress = addr;    /* 设备地址 				*/
    masterXfer.direction = kI2C_Write; /* 写入数据 				*/
    masterXfer.subaddress = reg;       /* 要写入的寄存器地址 			*/
    masterXfer.subaddressSize = 2;     /* 地址长度一个字节 			*/
    masterXfer.data = &writedata;      /* 要写入的数据 				*/
    masterXfer.dataSize = 1;           /* 写入数据长度1个字节			*/

    if (i2c_master_transfer(I2C2, &masterXfer))
        status = 1;

    return status;
}

/*
 * @description	: 从GT911读取一个字节的数据
 * @param - addr: 设备地址
 * @param - reg : 要读取的寄存器
 * @return 		: 读取到的数据。
 */
uint8_t GT911_read_byte(uint8_t addr, uint32_t reg)
{
    uint8_t val = 0;

    struct i2c_transfer masterXfer;
    masterXfer.slaveAddress = addr;   /* 设备地址 				*/
    masterXfer.direction = kI2C_Read; /* 读取数据 				*/
    masterXfer.subaddress = reg;      /* 要读取的寄存器地址 			*/
    masterXfer.subaddressSize = 2;    /* 地址长度一个字节 			*/
    masterXfer.data = &val;           /* 接收数据缓冲区 				*/
    masterXfer.dataSize = 1;          /* 读取数据长度1个字节			*/
    i2c_master_transfer(I2C2, &masterXfer);

    return val;
}

/*
 * @description	: 从GT911读取多个字节的数据
 * @param - addr: 设备地址
 * @param - reg : 要读取的开始寄存器地址
 * @param - len : 要读取的数据长度.
 * @param - buf : 读取到的数据缓冲区
 * @return 		: 无
 */
void GT911_read_len(uint8_t addr, uint32_t reg, uint32_t len, uint8_t *buf)
{
    struct i2c_transfer masterXfer;

    masterXfer.slaveAddress = addr;   /* 设备地址 				*/
    masterXfer.direction = kI2C_Read; /* 读取数据 				*/
    masterXfer.subaddress = reg;      /* 要读取的寄存器地址 			*/
    masterXfer.subaddressSize = 2;    /* 地址长度一个字节 			*/
    masterXfer.data = buf;            /* 接收数据缓冲区 				*/
    masterXfer.dataSize = len;        /* 读取数据长度1个字节			*/
    i2c_master_transfer(I2C2, &masterXfer);
}

/*
 * @description	: 向GT911多个寄存器写入数据
 * @param - addr: 设备地址
 * @param - reg : 要写入的开始寄存器地址
 * @param - len : 要写入的数据长度.
 * @param - buf : 写入到的数据缓冲区
 * @return 		: 无
 */
void GT911_write_len(uint8_t addr, uint32_t reg, uint32_t len, uint8_t *buf)
{
    struct i2c_transfer masterXfer;

    masterXfer.slaveAddress = addr;    /* 设备地址         */
    masterXfer.direction = kI2C_Write; /* 读取数据 	    */
    masterXfer.subaddress = reg;       /* 要读取的寄存器地址 */
    masterXfer.subaddressSize = 2;     /* 地址长度一个字节     */
    masterXfer.data = buf;             /* 接收数据缓冲区 	    */
    masterXfer.dataSize = len;         /* 读取数据长度1个字节  */
    i2c_master_transfer(I2C2, &masterXfer);
}

const uint16_t GT911_TPX_TBL[5] = {GT_TP1_REG, GT_TP2_REG, GT_TP3_REG, GT_TP4_REG, GT_TP5_REG};
/*
 * @description	: 读取当前所有触摸点的坐标
 * @param 		: 无
 * @return 		: 无
 */
void GT911_read_tpcoord(void)
{
    uint8_t buf[4];
    uint8_t regvalue = 0;

    regvalue = GT911_read_byte(GT911_ADDR, GT_GSTID_REG);
    GT911_write_byte(GT911_ADDR, GT_GSTID_REG, 0x00);
    GT911_dev.point_num = regvalue & 0XF; /* 计算读取了多少个点 */

    /* 读取当前所有的触摸坐标值 */
    for (uint8_t i = 0; i < GT911_dev.point_num; ++i)
    {
        GT911_read_len(GT911_ADDR, GT911_TPX_TBL[i], 4, buf); /* 读取坐标值 */
        GT911_dev.x[i] = ((u16)buf[1] << 8) + buf[0];
        GT911_dev.y[i] = (((u16)buf[3] << 8) + buf[2]);
    }
}

iomuxc.h

#ifndef __BSP_IOMUX_H
#define __BSP_IOMUX_H
#include "fsl_iomuxc.h"

// 用于简化寄存器位域的配置
#define configBits(data, bits, pos) ((data & bits) << pos)
#define ConfigBits(data, pos) (data << pos)

// 迟滞功能
#define IOMUXC_HYS_POS 16
#define IOMUXC_HYS_BITS 0x1
#define IOMUXC_HYS_Disable 0x0
#define IOMUXC_HYS_Enable 0x1

// 上拉/下拉功能
#define IOMUXC_PULL_POS 12
#define IOMUXC_PULL_BITS 0xF
#define IOMUXC_PULL_PUS_100K_DOWN 0x0 // 上下拉电阻配置
#define IOMUXC_PULL_PUS_47K_UP 0x4
#define IOMUXC_PULL_PUS_100K_UP 0x8
#define IOMUXC_PULL_PUS_22K_UP 0xC
#define IOMUXC_PULL_PUE_Keeper 0x0         // bit 13
#define IOMUXC_PULL_PUE_Pull 0x2           // bit 13
#define IOMUXC_PULL_PKE_Keeper_Disable 0x0 // bit 12
#define IOMUXC_PULL_PKE_Keeper_Enable 0x1  // bit 12

// 开漏功能
#define IOMUXC_ODE_POS 11
#define IOMUXC_ODE_BITS 0x1
#define IOMUXC_ODE_Disable 0x0
#define IOMUXC_ODE_Enable 0x1

// 速度功能
#define IOMUXC_SPEED_POS 6
#define IOMUXC_SPEED_BITS 0x3
#define IOMUXC_SPEED_LOW 0x0 // 速度配置官方手册比较模糊,就凑合配了一下
#define IOMUXC_SPEED_LOWPlus 0x1
#define IOMUXC_SPEED_MEDIUM 0x2
#define IOMUXC_SPEED_HIGH 0x3

// 驱动强度功能
#define IOMUXC_DSE_POS 3
#define IOMUXC_DSE_BITS 0x7
#define IOMUXC_DSE_Output_Driver_Disable 0x0
#define IOMUXC_DSE_R0_260Ohm 0x1
#define IOMUXC_DSE_R0_2 0x2 // R0/2
#define IOMUXC_DSE_R0_3 0x3
#define IOMUXC_DSE_R0_4 0x4
#define IOMUXC_DSE_R0_5 0x5
#define IOMUXC_DSE_R0_6 0x6
#define IOMUXC_DSE_R0_7 0x7

// 转换速率功能
#define IOMUXC_SRE_POS 0
#define IOMUXC_SRE_BITS 0x1
#define IOMUXC_SRE_Slow_Slew_Rate 0x0
#define IOMUXC_SRE_Fast_Slew_Rate 0x1

// 复用功能
#define IOMUXC_MUX_MODE_POS 0
#define IOMUXC_MUX_MODE_BITS 0x7
#define IOMUXC_ALT_0 0x0
#define IOMUXC_ALT_1 0x1
#define IOMUXC_ALT_2 0x2
#define IOMUXC_ALT_3 0x3
#define IOMUXC_ALT_4 0x4
#define IOMUXC_ALT_5 0x5
#define IOMUXC_ALT_6 0x6
#define IOMUXC_ALT_7 0x7
#define IOMUXC_ALT_8 0x8

// 软件输入功能
#define IOMUXC_SION_POS 4
#define IOMUXC_SION_BITS 0x1
#define IOMUXC_SION_Disable 0x0 // 输入路径由功能决定
#define IOMUXC_SION_Enable 0x1  // 强制输入路径

typedef struct
{
    uint8_t PULL : 4;  // 上拉/下拉
    uint8_t DSE : 3;   // 驱动强度
    uint8_t HYS : 1;   // 迟滞
    uint8_t SPEED : 2; // 速度
    uint8_t ODE : 1;   // 开漏
    uint8_t SRE : 1;   // 转换速率
    uint8_t SION : 1;  // 软件输入
} IOMUXC_InitTypeDef;

void IOMUXC_InitPin(uint32_t muxRegister,
                    uint32_t muxMode,
                    uint32_t inputRegister,
                    uint32_t inputDaisy,
                    uint32_t configRegister,
                    IOMUXC_InitTypeDef *IOMUXC_ConfigStruct);

#endif // !__BSP_IOMUX_H

iomuxc.c

#include "iomuxc.h"
void IOMUXC_InitPin(uint32_t muxRegister,
                    uint32_t muxMode,
                    uint32_t inputRegister,
                    uint32_t inputDaisy,
                    uint32_t configRegister,
                    IOMUXC_InitTypeDef *IOMUXC_ConfigStruct)
{
    *((volatile uint32_t *)muxRegister) = configBits(muxMode, IOMUXC_MUX_MODE_BITS, IOMUXC_MUX_MODE_POS) |
                                          configBits(IOMUXC_ConfigStruct->SION, IOMUXC_SION_BITS, IOMUXC_SION_POS);

    if (inputRegister)
    {
        *((volatile uint32_t *)inputRegister) = IOMUXC_SELECT_INPUT_DAISY(inputDaisy);
    }

    if (configRegister)
    {
        *((volatile uint32_t *)configRegister) = configBits(IOMUXC_ConfigStruct->DSE, IOMUXC_DSE_BITS, IOMUXC_DSE_POS) |
                                                 configBits(IOMUXC_ConfigStruct->HYS, IOMUXC_HYS_BITS, IOMUXC_HYS_POS) |
                                                 configBits(IOMUXC_ConfigStruct->ODE, IOMUXC_ODE_BITS, IOMUXC_ODE_POS) |
                                                 configBits(IOMUXC_ConfigStruct->PULL, IOMUXC_PULL_BITS, IOMUXC_PULL_POS) |
                                                 configBits(IOMUXC_ConfigStruct->SPEED, IOMUXC_SPEED_BITS, IOMUXC_SPEED_POS) |
                                                 configBits(IOMUXC_ConfigStruct->SRE, IOMUXC_SRE_BITS, IOMUXC_SRE_POS);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2071048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用ssm实现开放式教学评价管理系统+vue

TOC ssm121开放式教学评价管理系统vue 第1章 绪论 1.1 背景及意义 系统管理也都将通过计算机进行整体智能化操作&#xff0c;对于开放式教学评价管理系统所牵扯的管理及数据保存都是非常多的&#xff0c;例如个人中心、教师管理、学生管理、游客管理、评价信息管理、综合评…

如何系统化的学习 Redis?

搭建完整的知识框架和架构体系 张无剑&#xff1a;恭喜码哥&#xff0c;恭喜靓仔&#xff0c;网络资料很多&#xff0c;但碎片化严重&#xff0c;我如何才能成为 Redis 高手&#xff0c;建立完整的知识框架&#xff1f; Redis 是广受欢迎的 NoSQL 数据库&#xff0c;唯快不破是…

class_4:条件语句和逻辑运算符

mood_index int(input("对象今天的心情怎么样&#xff01;"))if mood_index > 80:print("今天可以好好happy一下了")print("O(∩_∩)O哈哈~") else:print("今天还是乖乖的吧&#xff01;否则小命不保") #BMI 体重 /&#xff08;身…

热血传奇经典1.85原始珍藏版单机安装教程+GM+假人+无需虚拟机

今天给大家带来一款单机游戏的架设&#xff1a;热血传奇经典1.85原始珍藏版。 另外&#xff1a;本人承接各种游戏架设&#xff08;单机联网&#xff09; 本人为了学习和研究软件内含的设计思想和原理&#xff0c;带了架设教程仅供娱乐。 教程是本人亲自搭建成功的&#xff0…

编程之路:在Bug的迷宫中寻找出口

编程是一种艺术&#xff0c;也是一种科学。它要求我们既要有创造性的思维&#xff0c;又要有严谨的逻辑。在这条充满挑战的道路上&#xff0c;每个人都会遇到挫折&#xff0c;这些挫折可能来自于一个难以解决的Bug&#xff0c;一个复杂的算法&#xff0c;或者是在实现某个功能时…

UDS诊断系列之十九 读取故障码(DTC)

一、读取符合条件的DTC数量 通过调用19服务的01子功能&#xff0c;我们可以轻松地读取符合特定条件的故障码数量。重要的是要意识到&#xff0c;此功能仅提供故障码的数量&#xff0c;而不包含任何额外的信息。这意味着&#xff0c;虽然你可以获得故障码的总数&#xff0c;但不…

【SQL】关注者数量

目录 题目 分析 代码 题目 表&#xff1a; Followers ------------------- | Column Name | Type | ------------------- | user_id | int | | follower_id | int | ------------------- (user_id, follower_id) 是这个表的主键&#xff08;具有唯一值的列的组合&am…

Global Context Vision Transformers

摘要 https://arxiv.org/pdf/2206.09959 我们提出了全局上下文视觉转换器&#xff08;GC ViT&#xff09;&#xff0c;这是一种新颖的架构&#xff0c;旨在提高计算机视觉中的参数和计算利用率。我们的方法利用全局上下文自注意力模块与标准的局部自注意力相结合&#xff0c;以…

通信协议学习:CAN总线协议

以下的学习主要是观看江科大视频后的总结&#xff0c;需要学习建议观看原视频&#xff1a;https://www.bilibili.com/video/BV1vu4m1F7Gt/?p1&spm_id_frompageDriver&vd_source0a52d160c212359f7f490eb9a868d174 CAN总线简介 CAN总线&#xff08;Controller Area Net…

selenium-java实现自动登录跳转页面

如果要一直刷新一个网页&#xff0c;总不能人工一直去点&#xff0c;所以想到大学时候学过selenium技术&#xff0c;写个脚本来一直刷新&#xff0c;因为经常写java语言&#xff0c;所以选用java语言来写 实验环境 注意&#xff0c;需要先准备好Google浏览器和Chrome-Driver驱…

mysql高可用之组复制 (MGR)

目录 1 MySQL的主从复制介绍 2 组复制流程 3 组复制单主和多主模式 3.1 single-primary mode(单写或单主模式) 3.2 multi-primary mode(多写或多主模式) 4 实现mysql组复制 4.1 MASTER 1 4.2 MASTER 2 4.3 MASTER 3 4.4 MASTER 1 检验 1 MySQL的主从复制介绍 MySQL Group Rep…

终端防火墙软件哪个好?2024年内网安全解决方案!

在2024年选择终端防火墙软件时&#xff0c;需要考虑多个因素&#xff0c;包括软件的防护能力、兼容性、管理便捷性、性能影响以及更新与维护等。 以下是一些在当前市场上表现优异的终端防火墙软件推荐&#xff0c;它们均能提供有效的内网安全解决方案&#xff1a; 1. 安企神 …

在HFSS中依据厂家模型自己进行连接器仿真---以SMP接口为例

在HFSS中依据厂家模型自己进行连接器仿真—以SMP接口为例 HFSS工程下载链接&#xff1a;在HFSS中依据厂家模型自己进行连接器仿真-以SMP接口为例-HFSS工程文件 在其他软件中仿真时&#xff0c;例如ADS、AWR等等&#xff0c;往往无法对连接头进行仿真。在HFSS中&#xff0c;我…

stm32f1xx中的几个ID

目录 一、ID的作用二、ID的说明产品唯一身份标识MCU ID codeJTAG IDJEDEC-106 ID 三、自定义ID 一、ID的作用 在物联网系统中产品的ID不可或缺&#xff0c;产品组网后就需要一个身份去让网里其它的设备去识别自己&#xff1b; ID表示的含义可能多种多样&#xff0c;如一个生产批…

一种多策略改进飞蛾扑火智能优化算法IMFO 种群初始化精英反向策略+柯西变异策略

一种多策略改进飞蛾扑火智能优化算法IMFO 种群初始化精英反向策略柯西变异策略 文章目录 前言一种多策略改进飞蛾扑火智能优化算法IMFO 种群初始化精英反向策略柯西变异策略 一、MFO飞蛾扑火算法基本原理二、改进飞蛾扑火算法IMFO改进1&#xff1a;种群初始化精英反向策略改进2…

车辆分类检测数据集数据集

车辆分类检测数据集 数据集中的所有车辆分为六类:客车、微型客车、小型货车、轿车、SUV和卡车。每种车型的车辆数量分别为558辆、883辆、476辆、5922辆、1392辆、822辆。 xml标签 数据集描述&#xff1a; 该数据集包含多种类型的车辆图像&#xff0c;旨在用于训练和评估车辆分…

【C++】string典型oj题

目录 前言字符串相加字符串相乘字符串转换整数 前言 上一节我们已经仔细讲解了关于string的各种重要接口的使用&#xff1a;【C】string的使用。下面我们来使用这些接口写几道OJ题。 字符串相加 415.字符串相加-力扣   这道题目的意思也很简单&#xff0c;就是想让我们模拟…

什么是d3dx9_42.dll?如何将丢失的d3dx9_42.dll进行修复呢?

d3dx9_42.dll文件丢失什么情况&#xff1f;如何将丢失的d3dx9_42.dll进行修复呢&#xff1f;d3dx9_42.dll又是什么文件&#xff1f;d3dx9_42.dll 文件是一个由 Microsoft Corporation 开发的部分&#xff0c;属于 Microsoft DirectX for Windows 的一组庞大库集合中的一个。Dir…

ShellSweepPlus 介绍:开源 Web Shell 检测

ShellSweepPlus 概述 ShellSweepPlus是一款开源工具,旨在帮助安全团队检测潜在的 Web Shell。它是 ShellSweep 的增强版 Webshell 的威胁 Web shell 对组织构成重大威胁,因为它们为攻击者提供了对受感染 Web 服务器的未经授权的访问和控制。攻击者可以利用这些 shell 来:…

AI跟踪报道第53期-新加坡内哥谈技术-本周AI新闻: 谷歌老施讲,微软Phi 3.5和Search GPT

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…