LINUX驱动开发AMG8833红外成像模块在HI3516上的应用

Posted 与光同程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LINUX驱动开发AMG8833红外成像模块在HI3516上的应用相关的知识,希望对你有一定的参考价值。

文章目录

AMG8833介绍

内部框图

可以看到AMG8833的内部有红外点阵测温,并且还带有一个热敏电阻。使用同一个ADC进行采样,然后送给Control。

器件参数

测温点数:64(8x8的矩阵)

帧率:10帧每秒或1帧每秒

红外测温分辨率:0.25℃

热敏电阻测量温度范围:-20℃~80℃

热敏电阻分辨率:0.0625℃

红外测温的准确度:High gain误差在2.5℃以内;Low gain误差在3℃以内。

点阵的排布顺序

从右到左、从下到上。因此右下角才是第一个点。

原理图

2脚和3脚是IIC通信引脚,最大速度400K。

4脚是中断引脚,如果INT control寄存器中激活了中断功能,当发生中断,此引脚会拉低。

5脚是IIC设备地址选择脚。拉低,设备地址为110 1000,即0x68。拉高,设备地址为110 1001,即0x69。

设备地址占据高7位,最低位是读写位,0表示写,1表示读。所以当5脚拉低,进行写操作时,8位数据为:1101 0000,即0xD0,读操作时,8位数据为:1101 0001,即0xD1。

6脚为地。

9脚和13脚为VDD,可以3.3V或5V供电。

10脚接一个电容和电阻。

12脚接一个电容。

内部寄存器

1、Power Control寄存器:

设置AMG8833的工作模式

2、Reset寄存器:

进行软复位。

有两种复位方式:

Flag Reset会清除Status寄存器(0x04)、中断标志、中断表(0x10~0x17)

Initial Reset会复位标志,并使AMG8833的参数恢复初始。

3、Frame Rate寄存器:设定帧率

bit0: Setting Frame Mode
1: 1FPS
0: 10FPS

4、Interrupt Control寄存器:

配置中断功能

bit1: INTMOD
1: Absolute Value Interrupt Mode
0: Difference Interrupt Mode
bit0: INTEN
1: INT 引脚输出使能
0: INT 引脚禁止输出(保持高阻状态)

5、Status寄存器:

溢出标志和中断标志

bit3: OVF_THS
1: 热敏电阻温度输出溢出标志
(Value of Thermistor (0x0E、0x0F) : 0xFFF)
bit2: OVF_IRS
1: 红外温度输出溢出标志
(Value of Temperature Register(0x80~0xFF): 0xFFF)
bit1: INTF
1: 发生中断标志
(Value of Interrupt Table Register(0x10~0x17): Except for 0x00)

6、Status Clear寄存器:

清除溢出标志和中断标志
bit3: OVT_CLR
1: 清除热敏电阻温度输出溢出标志
bit2: OVS_CLR
1: 清除红外温度输出溢出标志
bit1: INTCLR
1: 清除中断标志

7、Average寄存器:

设置移动平均输出模式
bit5: MAMOD
1::Twice moving average Output Mode

0:No moving average

8、Interrupt Level寄存器:

设置发生中断的上限值、下限值、迟滞值。

INT_LVL_H [11:0]:中断上限值,当温度高于此值,输出中断并且设置Interrupt Table寄存器。

INT_LVL_L [11:0]:中断下限值,当温度低于此值,输出中断并且设置Interrupt Table寄存器。

INT_HYS [11:0]:设置上限值、下限值的迟滞值,类似于施密特触发器。

上述3个数据都是12位数据。最高位为符号位,值为0表示正,值为1表示负。步进值为0.25℃。

9、Thermistor寄存器:

热敏电阻测量的温度值

有12位数据。最高位为符号位,值为0表示正,值为1表示负。步进值为0.0625℃。举例如下:

10、Interrupt Table寄存器:

显示哪一个像素点发生了中断

当64个像素点中的某一个点的温度值高于或低于了Interrupt Level寄存器中设置的上下限,就会在Interrupt Table寄存器的对应位设置值。值为1代表发生了中断,0表示没有。

11、Temperature寄存器:

红外点阵测量的温度值

有12位数据。最高位为符号位,值为0表示正,值为1表示负。步进值为0.25℃。举例如下:

0x80和0x81保存的是第一个像素的温度值,1-64像素对应地址为0x80~0xFF。

注:

(1)1 - 64像素(0x80~0xFF)的温度值是一起更新的,不需要任何指令。

(2)0x80~0xFF的数据是一次读出的,所以不用担心新的温度值和旧的温度值会混在一起。

HI3516驱动开发

为了避免麻烦,并且这里的传输数据量并不是非常大,所以直接用IO读取数据
所以如果要用其他LINUX开发板底层函数必须根据你们的板子重新编写。

/*
 * @Description: 
 * @Autor: YURI
 * @Date: 2022-01-21 17:14:06
 * @LastEditors: YURI
 * @LastEditTime: 2022-01-31 00:03:07
 */
#ifndef amg8833_H
#define amg8833_H

#define GPIO0_BASE_ADDR          	0x120D0000
#define GPIO0_DIR_ADDR            ((GPIO0_BASE_ADDR) + (0x400))
#define GPIO0_DATA_OUT_ADDR       ((GPIO0_BASE_ADDR) + (0x000))
#define GPIO0_DATA                ((GPIO0_BASE_ADDR) + (0x3FC))

#define GPIO1_BASE_ADDR          	0x120D1000
#define GPIO1_DIR_ADDR            ((GPIO1_BASE_ADDR) + (0x400))
#define GPIO1_DATA_OUT_ADDR       ((GPIO1_BASE_ADDR) + (0x000))
#define GPIO1_DATA                ((GPIO1_BASE_ADDR) + (0x3FC))

#define GPIO2_BASE_ADDR          	0x120D2000
#define GPIO2_DIR_ADDR            ((GPIO2_BASE_ADDR) + (0x400))
#define GPIO2_DATA_OUT_ADDR       ((GPIO2_BASE_ADDR) + (0x000))
#define GPIO2_DATA                ((GPIO2_BASE_ADDR) + (0x3FC))

#define GPIO3_BASE_ADDR          	0x120D3000
#define GPIO3_DIR_ADDR            ((GPIO3_BASE_ADDR) + (0x400))
#define GPIO3_DATA_OUT_ADDR       ((GPIO3_BASE_ADDR) + (0x000))
#define GPIO3_DATA                ((GPIO3_BASE_ADDR) + (0x3FC))

#define GPIO4_BASE_ADDR          	0x120D4000
#define GPIO4_DIR_ADDR            ((GPIO4_BASE_ADDR) + (0x400))
#define GPIO4_DATA_OUT_ADDR       ((GPIO4_BASE_ADDR) + (0x000))
#define GPIO4_DATA                ((GPIO4_BASE_ADDR) + (0x3FC))

#define GPIO5_BASE_ADDR          	0x120D5000
#define GPIO5_DIR_ADDR            ((GPIO5_BASE_ADDR) + (0x400))
#define GPIO5_DATA_OUT_ADDR       ((GPIO5_BASE_ADDR) + (0x000))
#define GPIO5_DATA                ((GPIO5_BASE_ADDR) + (0x3FC))

#define GPIO6_BASE_ADDR          	0x120D6000
#define GPIO6_DIR_ADDR            ((GPIO6_BASE_ADDR) + (0x400))
#define GPIO6_DATA_OUT_ADDR       ((GPIO6_BASE_ADDR) + (0x000))
#define GPIO6_DATA                ((GPIO6_BASE_ADDR) + (0x3FC))

#define GPIO7_BASE_ADDR          	0x120D7000
#define GPIO7_DIR_ADDR            ((GPIO7_BASE_ADDR) + (0x400))
#define GPIO7_DATA_OUT_ADDR       ((GPIO7_BASE_ADDR) + (0x000))
#define GPIO7_DATA                ((GPIO7_BASE_ADDR) + (0x3FC))

#define GPIO8_BASE_ADDR          	0x120D8000
#define GPIO8_DIR_ADDR            ((GPIO8_BASE_ADDR) + (0x400))
#define GPIO8_DATA_OUT_ADDR       ((GPIO8_BASE_ADDR) + (0x000))
#define GPIO8_DATA                ((GPIO8_BASE_ADDR) + (0x3FC))

#define GPIO9_BASE_ADDR          	0x120D9000
#define GPIO9_DATA_OUT_ADDR       ((GPIO9_BASE_ADDR) + (0x000))
#define GPIO9_SET_DATA_ADDR       ((GPIO9_DATA_OUT_ADDR) + (0x200))
#define GPIO9_DATA                ((GPIO9_BASE_ADDR) + (0x3FC))

#define GPIO10_BASE_ADDR          	0x120DA000
#define GPIO10_DIR_ADDR            ((GPIO10_BASE_ADDR) + (0x400))
#define GPIO10_DATA_OUT_ADDR       ((GPIO10_BASE_ADDR) + (0x000))
#define GPIO10_DATA                ((GPIO10_BASE_ADDR) + (0x3FC))

#define GPIO11_BASE_ADDR          	0x120DB000
#define GPIO11_DIR_ADDR            ((GPIO11_BASE_ADDR) + (0x400))
#define GPIO11_DATA_OUT_ADDR       ((GPIO11_BASE_ADDR) + (0x000))
#define GPIO11_DATA                ((GPIO11_BASE_ADDR) + (0x3FC)) 
enum amg8833_pin_directionamg8833_IN=0,amg8833_OUT=1;

#define AMG8833_DELAY_TIME  4

//amg8833 关键控制器
typedef struct 

    volatile unsigned long *pin_mutx;   //管脚选择地址
    volatile unsigned long *pin_dir;    //管脚方向地址
    volatile unsigned long *pin_data;//控制管脚的数据组在的位置
    volatile int pin_index;             //管脚号
amg8833_pin;

//amg8833 硬件控制器
typedef struct 

    amg8833_pin *sck;        // 时钟
    amg8833_pin *sda;        // 数据线
    amg8833_pin *inter;      // 中断线
    amg8833_pin *ad0;        // 地址选择
amg8833_ctl;


#define AMG88xx_PIXEL_TEMP_CONVERSION 0.25
#define AMG88xx_THERMISTOR_CONVERSION 0.0625
enum

	AMG88xx_PCTL = 0x00,
	AMG88xx_RST = 0x01,
	AMG88xx_FPSC = 0x02,
	AMG88xx_INTC = 0x03,
	AMG88xx_STAT = 0x04,
	AMG88xx_SCLR = 0x05,
	//0x06 reserved
	AMG88xx_AVE = 0x07,
	AMG88xx_INTHL = 0x08,
	AMG88xx_INTHH = 0x09,
	AMG88xx_INTLL = 0x0A,
	AMG88xx_INTLH = 0x0B,
	AMG88xx_IHYSL = 0x0C,
	AMG88xx_IHYSH = 0x0D,
	AMG88xx_TTHL = 0x0E,
	AMG88xx_TTHH = 0x0F,
	AMG88xx_INT_OFFSET = 0x010,
	AMG88xx_PIXEL_OFFSET = 0x80
;
enum power_modes
	AMG88xx_NORMAL_MODE = 0x00,
	AMG88xx_SLEEP_MODE = 0x01,
	AMG88xx_STAND_BY_60 = 0x20,
	AMG88xx_STAND_BY_10 = 0x21
;
enum sw_resets 
	AMG88xx_FLAG_RESET = 0x30,
	AMG88xx_INITIAL_RESET = 0x3F
;
enum frame_rates 
	AMG88xx_FPS_10 = 0x00,
	AMG88xx_FPS_1 = 0x01
;
enum int_enables
	AMG88xx_INT_DISABLED = 0x00,
	AMG88xx_INT_ENABLED = 0x01
;
enum int_modes 
	AMG88xx_DIFFERENCE = 0x00,
	AMG88xx_ABSOLUTE_VALUE = 0x01
;
#define AMG88xx_ADR    0xD0          //5脚拉低时的设备地址
 
#endif
/*
 * @Description: 
 * @Autor: YURI
 * @Date: 2022-01-30 17:18:51
 * @LastEditors: YURI
 * @LastEditTime: 2022-01-31 00:33:38
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <linux/slab.h> 
#include <asm/io.h>
#include <linux/delay.h>
#include "amg8833.h"
amg8833_ctl amg8833;
#define DEVICE_NAME "amg8833" 

/**
 * @description: amg8833 管脚初始化
 * @param unsigned long base_addr
 * @param unsigned long mutex_addr
 * @param int mutex_select
 * @param int pin_direction
 * @param int pinindex
 * @param int pindefaultvalue
 * @return *
 * @author: YURI
 */
static amg8833_pin* amg8833_pin_init(unsigned long base_addr,unsigned long mutex_addr,int mutex_select,int pin_direction,int pinindex,int pindefaultvalue)

    amg8833_pin* pin=(amg8833_pin*)kmalloc(sizeof(amg8833_pin),GFP_KERNEL);
    pin->pin_dir     = (volatile unsigned long *)ioremap(base_addr+(0x400), 32);//方向选择寄存器
    pin->pin_data    = (volatile unsigned long *)ioremap(base_addr+(0x3FC), 32);//数据寄存器
    pin->pin_mutx    = (volatile unsigned long *)ioremap(mutex_addr, 32);       //功能选择寄存器
    
    pin->pin_index   = pinindex;
    *(pin->pin_data)|=(pindefaultvalue<<pinindex);
    *(pin->pin_mutx)=mutex_select;
    *(pin->pin_dir )=(pin_direction<<pinindex);
    return pin;
 
/**
 * @description: amg8833 管脚恢复
 * @param amg8833_pin* pin
 * @return *
 * @author: YURI
 */
static void amg8833_pin_uninit(amg8833_pin* pin)

    iounmap(pin->pin_data);
    iounmap(pin->pin_mutx);
    iounmap(pin->pin_dir);
    kfree(pin);

/**
 * @description: 改变输入输出方向
 * @param amg8833_pin* pin
 * @param int pin_direction
 * @return *
 * @author: YURI
 */
static inline void amg8833_pin_change_direction(amg8833_pin* pin,int pin_direction)

    *(pin->pin_dir )=(pin_direction<<pin->pin_index);

/**
 * @description: 设置管脚数值
 * @param amg8833_pin* pin
 * @param int value
 * @return *
 * @author: YURI
 */
static inline void amg8833_pin_change_value(amg8833_pin* pin,int value)

    //printk("KERNEL VALUE %d",value);
   if(value) *(pin->pin_data)|=(1<<(pin->pin_index));
   else *(pin->pin_data)&=~(1<<(pin->pin_index));

/**
 * @description: 反转管脚
 * @param amg8833_pin* pin
 * @return *
 * @author: YURI
 */
static inline void amg8833_pin_toggle_value(amg8833_pin* pin)

   if(*(pin->pin_data)&(1<<(pin->pin_index))) *(pin->pin_data)&=~(1<<(pin->pin_index));
   else *(pin->pin_data)|=(1<<(pin->pin_index));

/**
 * @description: 获取管脚电平
 * @param amg8833_pin* pin
 * @return *
 * @author: YURI
 */
static inline int amg8833_pin_get_value(amg8833_pin* pin)

    if(*(pin->pin_data)&(1<<(pin->pin_index)))return 1;
    else return 0;

/**
 * @description: amg8833结构体初始化,初始化所有管脚
 * @param *
 * @return *
 * @author: YURI
 */
static void amg8833_ctl_init(void)

    amg8833.sck   =amg8833_pin_init(GPIO0_BASE_ADDR,0X112F0034,0X520,amg8833_OUT,6,0);//0_6
    amg8833.sda   =amg8833_pin_init(GPIO2_BASE_ADDR,0X114F0068,0X520,amg8833_OUT,3,0);//2_3
    amg8833.inter =amg8833_pin_init(GPIO8_BASE_ADDR,0X112F0040,0X524,amg8833_OUT,7,0);//8_7
    amg8833.ad0   =amg8833_pin_init(GPIO7_BASE_ADDR,0X112F0044,0X520,amg8833_OUT,0,0);//7_0

/**
 * @description: 释放硬件资源
 * @param *
 * @return *
 * @author: YURI
 */
static void amg8833_ctl_uninit(void)

    amg8833_pin_uninit(amg8833.sck);
    amg8833_pin_uninit(amg8833.sda);
    amg8833_pin_uninit(amg8833.inter);
    amg8833_pin_uninit(amg8833.ad0);


/**
 * @description:IIC开始信号 当SLK高电平 SDA由高变低
 * @param *
 * @return *
 * @author: YURI
 */
void amg_iic_start(void)

    amg8833_pin_change_direction(amg8833.sda,amg8833_OUT);
    amg8833_pin_change_value(amg8833.sda,1);
    amg8833_pin_change_value(amg8833.sck,1);
    udelay(AMG8833_DELAY_TIME);
    amg8833_pin_change_value(amg8833.sda,0);
    udelay(AMG8833_DELAY_TIME);
    amg8833_pin_change_value(amg8833.sck,0);


/**
 * @description:IIC结束信号 当SLK高电平 SDA由低变高
 * @param *
 * @return *
 * @author: YURI
 */
void amg_iic_stop(void)

    amg8833_pin_change_direction(amg8833.sda,amg8833_OUT);
    amg8833_pin_change_value(amg8833.sck,0);
    amg8833_pin_change_value(amg8833.sda,0);
    udelay(AMG8833_DELAY_TIME);
    amg8833_pin_change_value(amg8833.sck,1);
    amg8833_pin_change_value(amg8833.sda,1);
    udelay(AMG8833_DELAY_TIME);

/**
 * @description: 主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答
 * @param *
 * @return *
 * @author: YURI
 */
unsigned char amg_iic_wait_ack(void)

    unsigned char ucErrTime=0;
    amg8833_pin_change_direction(amg8833.sda,amg8833_IN);
    amg8833_pin_change_value(amg8833.sda,1);udelay(AMG8833_DELAY_TIME);
    amg8833_pin_change_value(amg8833.sck,1);udelay(AMG8833_DELAY_TIME);
   	while(amg8833_pin_get_value(amg8833.sda))
	
		ucErrTime++;
		if(ucErrTime>250)
		
			amg_iic_stop();
			return 1;
		
	
	amg8833_pin_change_value(amg8833.sck,0);//时钟输出0 	   
	return 0;   


//产生ACK应答
//1.先拉低SCL,再拉低SDA
//2.拉高SCL
//3.拉低SCL
void amg_iic_ack(void)

    amg8833_pin_change_value(amg8833.sck,0);
    amg8833_pin_change_direction(amg8833.sda,amg8833_OUT);
    amg8833_pin_change_value(amg8833.sda,0);
	udelay(AMG8833_DELAY_TIME/2);
	amg8833_pin_change_value(amg8833.sck,1);
	udelay(AMG8833_DELAY_TIME/2);
	amg8833_pin_change_value(amg8833.sck,0);

 
//不产生ACK应答	
//1.先拉低SCL,再拉高SDA
//2.拉高SCL
//3.拉低SCL	    
void amg_iic_nack(void)

    amg8833_pin_change_value(amg8833.sck,0);
    amg8833_pin_change_direction(amg8833.sda,amg8833_OUT);
    amg8833_pin_change_value(amg8833.sda,1);
	udelay(AMG8833_DELAY_TIME/2);
	amg8833_pin_change_value(amg8833.sck,1);
	udelay(AMG8833_DELAY_TIME/2);
	amg8833_pin_change_value(amg8833.sck,0);


//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void amg_iic_send_byte(unsigned char txd)
                        
    unsigned char t;   
	amg8833_pin_change_direction(amg8833.sda,amg8833_OUT);   
    amg8833_pin_change_value(amg8833.sck,0);//拉低时钟开始数据传输
    for(t=0;t<8;t++)
                  
		if((txd&0x80)>>7)
			amg8833_pin_change_value(amg8833.sda,1);
		else
			amg8833_pin_change_value(amg8833.sda,0);
		txd<<=1; 	  
		udelay(AMG8833_DELAY_TIME/2);  
		amg8833_pin_change_value(amg8833.sck,1);
		udelay(AMG8833_DELAY_TIME/2); 
		amg8833_pin_change_value(amg8833.sck,0);	
		udelay(AMG8833_DELAY_TIME/2);
    	 
 
 
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
unsigned char amg_iic_read_byte(void)

	unsigned char i,receive=0;
	amg8833_pin_change_direction(amg8833.sda,amg8833_IN);
	amg8833_pin_change_value(amg8833.sda,1);;
	udelay(4);
	for(i=0;i<8;i++ )
	
		receive<<=1;
		amg8833_pin_change_value(amg8833.s

以上是关于LINUX驱动开发AMG8833红外成像模块在HI3516上的应用的主要内容,如果未能解决你的问题,请参考以下文章

ESP32+AMG8833+RGB屏240*320(ST7789)红外热成像

AMG8833 8x8热成像传感器

AMG8833 8x8热成像传感器

MLX90640 红外热成像传感器测温模块开发笔记

MLX90640 红外热成像仪测温模块开发笔记(完整篇)

MLX90640 红外热成像仪测温传感器模块开发笔记