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

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

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

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

简介:

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

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

启发:

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

cpp 复制代码
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);
}

尝试:

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

cpp 复制代码
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次(不同的芯片、板子可能不同)。虽然可行,但终究多了一步,感觉有些浪费

cpp 复制代码
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中断开启之后,板子中断开启之前对芯片清零,于是初始化代码变成了

cpp 复制代码
    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);

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

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

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

cpp 复制代码
/*----------------中断前清零--------------------*/
    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次左右即可解决问题,当然具体情况具体讨论,在这个参考上调整一下。

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

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

Touch.h源码

cpp 复制代码
#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源码

cpp 复制代码
#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

cpp 复制代码
#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

cpp 复制代码
#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);
    }
}
相关推荐
阿川!3 小时前
嵌入式软件--51单片机 DAY 4
单片机·嵌入式硬件·51单片机
好家伙VCC5 小时前
嵌入式 面试单片机面试题目分析和答案 IIC总线 IIC协议 SPI总线 I2C协议讲解 SPI和IIC协议对比比较SPI的工作模式比较 IIC基本概念讲解
单片机·嵌入式硬件
秋风&萧瑟5 小时前
【STM32】CAN总线基础入门
stm32·单片机·嵌入式硬件
LCMICRO-133108477466 小时前
长芯微LS5541/LS5542国产数模转换芯片DAC完全替代P2P替代AD5541/AD5542
单片机·嵌入式硬件·fpga开发·硬件工程·dsp开发
浅陌pa7 小时前
19:I2C一:程序模拟I2C通信时序
stm32·单片机·嵌入式硬件
7yewh7 小时前
STM32常用数据采集滤波算法
stm32·嵌入式硬件·算法
Chambor_mak8 小时前
stm32单片机个人学习笔记1(简单介绍)
stm32·单片机·学习
lantiandianzi9 小时前
基于单片机的热成像测温显示系统设计
单片机·嵌入式硬件