Tiny4412之重力感应器驱动
一:Tiny4412 裸板重力感应驱动编写
整个编写过程大概分为如下几步:
(1)在底板上找到重力感应器的所在位置,找到芯片型号(我用的板子上重力感应器芯片型号为:MMA7660FC)
(2)通过型号查看重力感应器电路图,了解每个引脚的功能
(3)找到引脚对应的网标(EINT,SDL,SCL)配置其相应的gpio口
(4)配置芯片相关寄存器
(5)使用I2C来读取重力感应器相应寄存器的值
下面是整个驱动的简单流程图:
通过看底板我们知道了重力感应器的控制芯片型号为:MMA7660FC,接下来我们就在看看改芯片的电路图(如下):
由上图我们可以看出它的外部中断XEINT25,用到的i2c总线为SDA3、SCL3
通过网标我们可以看到它是怎么连接到核心板上的(soc)
由上图可知,XEINT25、I2CSDA3、SCL3所对应的gpio分别为GPA1_2、GPA1_3、GPX3_1,之后我们就可以配置gpio口为相应的功能
通过datasheet我们可以找到它的外部中断号为64,如下图:
简单了解了mma7660的电路图之后我们就需要看芯片的datasheet,了解里面寄存器的配置及功能
首先看一下整个芯片与我们核心板的连接图:
由上图我们可以看出,芯片连接到我们核心板(soc)的总共为三根线:INT( 中断信号),SDA、SCL(通i2c来进行寄存器的配置和读取)
下面看一下该芯片的几种工作模式:
今天我们实验的所需要的就是就当板子在晃动的时候它会出发中断,我们利用i2c来读取它相应寄存器的值,来判断前后左右以及X、Y、Z的值
下面是该芯片的寄存器及功能:
由上图我们可以看出寄存器:0x00、0x01、0x02它的底六位分别存储着对应的X、Y、Z的值,因此在之后的试验中我们就可以利用i2c来读取它里面的值
0x03这个寄存器的具体功能如下所所示、它里面存储了前后左右上下的值:
下面的几个寄存器是我们需要配置的:
这个寄存是:该芯片里面的中断寄存器,我们需要配置相应值来响应中断,光配置外部中断是不可以的,我们需要配置该寄存器来响应我们的外部中断
该寄存器是配置相应的模式,我们需要配置它为shake,当我们在晃动板子是可以出发中断;配置好这两个寄存器之后,我们就可以使用I2C来读取对应寄存器的值了
接下来我们需要做的就是设置相应的gpio口,以及配置好I2C的相应寄存器:
I2C总线驱动在上一篇中已经介绍了,I2C总线设备分为四种模式:主端发送、主端接收,从端发送、从端接收,在该驱动中我们用到的只有主发跟主收,下面是相应的流程图,整个I2C的读写都是按照这个流程:
主端发送:
主端接收:
配置好整个I2C之后我们就可以对芯片进行相应的设置和读取了,下面贴出真个重力感应驱动的代码:
#ifndef __REGS_H
#define __REGS_H #define printf(...) (((int (*)(const char *, ...))0xc3e114d8)(__VA_ARGS__)) #define GPA1CON (*(volatile unsigned long *)0x11400020)
#define I2CCON3 (*(volatile unsigned long *)0x13890000)
#define I2CADD3 (*(volatile unsigned long *)0x13890008)
#define I2CSTAT3 (*(volatile unsigned long *)0x13890004)
#define I2CDS3 (*(volatile unsigned long *)0x1389000C)
#define I2CLC3 (*(volatile unsigned long *)0x13890010) #define GPD1CON (*(volatile unsigned long *)0x114000C0)
#define GPD1PUD (*(volatile unsigned long *)0x114000C8)
#define I2CCON1 (*(volatile unsigned long *)0x13870000)
#define I2CADD1 (*(volatile unsigned long *)0x13870008)
#define I2CSTAT1 (*(volatile unsigned long *)0x13870004)
#define I2CDS1 (*(volatile unsigned long *)0x1387000C)
#define I2CLC1 (*(volatile unsigned long *)0x13870010) #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000)
#define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004)
#define ICDDCR (*(volatile unsigned long *)0x10490000)
#define ICDIPR15_CPU0 (*(volatile unsigned long *)0x1049043C)
#define ICDIPTR15_CPU0 (*(volatile unsigned long *)0x1049083C)
#define ICDISER1_CPU0 (*(volatile unsigned long *)0x10490104)
#define ICDSGIR (*(volatile unsigned long *)0x10490f00)
#define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000C)
#define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010) #define GPX1CON (*(volatile unsigned long *)0x11000C20) #define EXT_INT41_CON (*(volatile unsigned long *)0x11000E04)
#define EXT_INT41_MASK (*(volatile unsigned long *)0x11000F04)
#define EXT_INT41_PEND (*(volatile unsigned long *)0x11000F44) #define GPX3CON (*(volatile unsigned long *)0x11000c60)
#define GPX3DAT (*(volatile unsigned long *)0x11000c64)
#define GPD0CON (*(volatile unsigned long *)0x110000a0)
#define GPD0DAT (*(volatile unsigned long *)0x110000a4) #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000)
#define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004)
#define ICDDCR (*(volatile unsigned long *)0x10490000)
#define ICDIPR16_CPU0 (*(volatile unsigned long *)0x10490440)
#define ICDIPTR16_CPU0 (*(volatile unsigned long *)0x10490840)
#define ICDISER2_CPU0 (*(volatile unsigned long *)0x10490108)
#define ICDSGIR (*(volatile unsigned long *)0x10490f00)
#define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000C)
#define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010) #define EXT_INT43_CON (*(volatile unsigned long *)0x11000E0C)
#define EXT_INT43_MASK (*(volatile unsigned long *)0x11000F0C)
#define EXT_INT43_PEND (*(volatile unsigned long *)0x11000F4C) #endif
regs.h
#ifndef __MMA_H
#define __MMA_H void mma_set();
void mma_read();
void i2c_gpio_set();
int master_write(unsigned char slaveaddr, unsigned char subaddr, unsigned char *data);
int master_read(unsigned char slaveaddr, unsigned char subaddr, unsigned char *data);
void i2c_init();
void i2c_exit();
void irq_init();
void do_irq();
void enable_mmu();
void init_table(unsigned long *addr);
void memcpy(unsigned char *dest, unsigned char *src, unsigned int len); extern unsigned long vector_start; #endif //MMA_H
#include "mma.h"
#include "regs.h" void (*udelay)(int ) = 0xc3e04fec; int main(void)
{
*(unsigned long *)0x47000000 = do_irq;
enable_mmu();
i2c_gpio_set();
mma_set();
irq_init();
memcpy(0x0, vector_start, 0x1000);
} void do_irq()
{
if(EXT_INT43_PEND & ( << )) {//judge interrupt occurs
EXT_INT43_PEND |= ( << );//clear interrupt
mma_read();
}
} void mma_set()
{
/*$06: Interrupt Setup Register
0x98 <--> 芯片地址 0x6 <---> 寄存器地址
*/
master_write(0x98, 0x6, 0xe3); // e3 1110 0011
/*
-----------------------------------------------------------
D7 D6 D5 D4 D3 D2 D1 D0
SHINTX SHINTY SHINTZ GINT ASINT PDINT PLINT FBINT
1 1 1 0 0 0 1 1
-----------------------------------------------------------
FBINT
0: Front/Back position change does not cause an interrupt
1: Front/Back position change causes an interrupt
PLINT
0: Up/Down/Right/Left position change does not cause an
interrupt
1: Up/Down/Right/Left position change causes an interrupt
PDINT
0: Successful tap detection does not cause an interrupt
1: Successful tap detection causes an interrupt
ASINT
0: Exiting Auto-Sleep does not cause an interrupt
1: Exiting Auto-Sleep causes an interrupt
GINT
0: There is not an automatic interrupt after every
measurement
1: There is an automatic interrupt after every measurement,
SHINTX
0: Shake on the X-axis does not cause an interrupt or set the
Shake bit in the TILT register
1: Shake detected on the X-axis causes an interrupt, and sets
the Shake bit in the TILT register
SHINTY
0: Shake on the Y-axis does not cause an interrupt or set the
Shake bit in the TILT register
1: Shake detected on the Y-axis causes an interrupt, and sets
the Shake bit in the TILT register
SHINTZ
0: Shake on the Z-axis does not cause an interrupt or set the
Shake bit in the TILT register
1: Shake detected on the Z-axis causes an interrupt, and sets
the Shake bit in the TILT register. */ /*$07: Mode Register (Read/Write)*/
master_write(0x98, 0x7, 0xd9); //d9 1101 1001
/*
-----------------------------------------------------------
D7 D6 D5 D4 D3 D2 D1 D0
IAH IPP SCPS ASE AWE TON - MODE
1 1 0 1 1 0 0 1
-----------------------------------------------------------
MODE
0: Standby mode or Test Mode depending on state of TON
1: Active mode
TON
0: Standby Mode or Active Mode depending on state of MODE
1: Test Mode
AWE
0: Auto-Wake is disabled
1: Auto-Wake is enabled.
ASE
0: Auto-Sleep is disabled
1: Auto-Sleep is enabled
SCPS
0: The prescaler is divide-by-1. The 8-bit internal Sleep
Counter input clock is the samples per second set by
AMSR[2:0]
1: Prescaler is divide-by-16. The 8-bit Sleep Counter input
clock is the samples per second set by AMSR[2:0] divided by
16,
IPP
0: Interrupt output INT is open-drain.
1: Interrupt output INT is push-pull
IAH
0: Interrupt output INT is active low
1: Interrupt output INT is active high
*/
} void mma_read()
{
unsigned char val;
unsigned char i;
for(i = ; i < ; i++)
while() {
master_read(0x98, i, &val); //read
if((val & ( << )) == ) {
if( == i) {
printf("X is %d\n", 0x3f & val); //6-bit output value X
}
if( == i) {
printf("Y is %d\n", 0x3f & val); //6-bit output value Y
}
if( == i) {
printf("Z is %d\n", 0x3f & val); //6-bit output value Z
}
if( == i) {
/*BaFro[1:0]
*01: Front
*10: Back
*/
if((val & ) == )
printf("Front\n"); if((val & ) == )
printf("Back\n");
/*PoLa[2:0]
* 001: Left
* 010: Right
* 101: Down
* 110: Up
* */
if(((val >> ) & 0x7) == )
printf("Left\n"); if(((val >> ) & 0x7) == )
printf("Right\n"); if(((val >> ) & 0x7) == )
printf("Down\n"); if(((val >> ) & 0x7) == )
printf("Up\n"); }
break;
}
}
} int master_write(unsigned char slaveaddr, unsigned char subaddr, unsigned char *data)
{
i2c_init(); unsigned char timeout = ;
while(timeout) {
udelay();
if(!(I2CSTAT3 & ( << ))){ //judge I2C-bus busy signal (0 busy or no busy)
I2CCON3 |= ( << ); //I2C-bus acknowledge enable
I2CDS3 = slaveaddr; // slave addr
I2CSTAT3 = 0xf0; // Master transmit mode
udelay(); timeout = ;
while(timeout) {
udelay();
if(I2CCON3 & ( << )) {//Interrupt is pending
I2CDS3 = subaddr; //register addr
udelay();
I2CCON3 &= ~( << ); //Clears pending condition and resumes the operation
udelay();
break;
}
timeout --;
}
if( == timeout)
return -; timeout = ;
while(timeout) {
udelay(); if(I2CCON3 & ( << )) { // interrupt is pending
I2CDS3 = data; //write data
udelay();
I2CCON3 &= ~( << ); //Clear pending bit to resume.(每次都要写0才会发送)
udelay();
break;
}
timeout--;
if( == timeout)
return -;
} timeout = ;
while(timeout) {
udelay();
if(I2CCON3 & ( << )) {//interrupt is pending
I2CSTAT3 = 0xd0; //Master transmit mode stop
udelay();
I2CCON3 &= ~( << );
udelay();
break;
}
timeout--;
}
if( == timeout)
return -; while( == (I2CSTAT3 & ( << ))) {// Wait until the stop condition takes effect
;
}
i2c_exit(); //exit i2c
return ;
}
timeout--;
}
return -;
} int master_read(unsigned char slaveaddr, unsigned char subaddr, unsigned char *data)
{
i2c_init();
unsigned char count = ;
unsigned char buf[];
unsigned char timeout = ; //-------------write------------------
while(timeout)
{
udelay();
if(!(I2CSTAT3 & ( << )))//判断忙与不忙
{
I2CCON3 |= ( << ); //开启I2C总线ack信号
I2CDS3 = slaveaddr; //写入要读的芯片地址
I2CSTAT3 = 0xf0; //选择主端发送模式
udelay();
timeout = ;
while(timeout)
{
udelay();
if( I2CCON3 & (<<)) //等待中断(ACK信号)
{
I2CDS3 = subaddr; //写入要读的寄存器地址
udelay();
I2CCON3 &= ~( << ); //向这一位写0,发送,清楚等待条件,恢复操作
udelay();
break; }
timeout--;
}
if( == timeout)
return -;
timeout = ;
while(timeout)
{
udelay();
if(I2CCON3 & ( << ))
{
I2CSTAT3 = 0xd0; //set Read Not busy (If Read)
udelay();
I2CCON3 &= ~(<<);
udelay();
break;
}
timeout--;
}
if( == timeout)
return -; //------------read------------------
timeout = ;
while(timeout)
{
udelay();
if(!(I2CSTAT3 & ( << )))
{
I2CCON3 |= ( << );
I2CDS3 = slaveaddr;//写入芯片地址
I2CSTAT3 = 0xb0; //选择主端接收模式
udelay();
break;
}
timeout--;
}
if( == timeout)
return -; timeout = ;
while(timeout)
{
udelay();
if(I2CCON3 & ( << ))
{
buf[count] = I2CDS3; //read
count++;
if( == count)
I2CCON3 &= ~( << );//I2C-bus acknowledge Disable I2CCON3 &= ~( << ); //Clear pending bit to resume
udelay();
if( == count)
break;
}
timeout--;
}
if( == timeout)
return -; timeout = ;
while(timeout)
{
udelay();
if(I2CCON3 & ( << ))//wait ack
{
I2CSTAT3 = 0x90;//主端接受模式结束
I2CCON3 &= ~( << );
udelay();
break;
}
timeout--;
}
if( == timeout)
return -; while( == (I2CSTAT3 & ( << ))) //Wait until the stop condition takes effect {
printf("in while read \n");;
}
i2c_exit(); //exit i2c
*data = buf[subaddr + ]; return ;
}
timeout--;
}
return -;
} /*SDA3 <---> GPA1_2 SCL3 <-->GPA1_3 */
void i2c_gpio_set()
{
printf("i2c_gpio_set\n");
GPA1CON &= ~(0xff << );
GPA1CON |= (0x33 << );
} void i2c_init()
{
I2CCON3 = | ( << ) | ( << );
I2CSTAT3 = ( << );
I2CLC3 = 0x7;
} void i2c_exit()
{
I2CCON3 = ;
I2CSTAT3 = ;
I2CLC3 = ; } void irq_init()
{
//step 1: enable cpu cpsr
__asm__ __volatile__(
"mrs r0, cpsr\n"
"bic r0, r0, #0x80\n"
"msr cpsr, r0\n"
::: "r0"
); //step 2: GIC NO.62
ICCICR_CPU0 = ;//global enable interrupt (total switch)
ICCPMR_CPU0 = 0xff;//This register provides an interrupt priority filter.
ICDDCR = ;//This register enables forwarding of pending interrupts to the CPU interfaces /*一共有1024个中断源,只有160个中断号*/
//id = 64. 一个ICDIPR 控制4个中断,64 / 4 = 16 ...0, so ICDIPR=16
ICDIPR16_CPU0 = ( << );//the zero is the highest priority
ICDIPTR16_CPU0 = ( << );//0x1 ---> for cpu0
ICDISER2_CPU0 = ( << );// enable interrupt 0 //step 4:set ext_int
EXT_INT43_CON &= ~(0xf << );
EXT_INT43_CON |= (0x4 << );//falling edge; low level
EXT_INT43_MASK = ;//enable extint43_1 //step 3: set gpio
GPX3CON &= ~(0xf << );
GPX3CON |= (0xf << );//xeint25 <==> gpx3_1 ---->0xF = EXT_INT43[1] printf("irq over\n");
} void enable_mmu()
{
/*构建表*/
unsigned long addr = 0x50000000;
init_table(addr); /*打开mmu*/
unsigned long mmu = ;
mmu = | ( << ) | ( << ) | ( << ); __asm__ __volatile__ (
"mov r0, #3\n"
"MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员
"MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址
"MCR p15, 0, %1, c1, c0, 0\n"//开启mmu
:
: "r" (addr), "r" (mmu)
:
); } void init_table(unsigned long *addr)
{
unsigned long va = ;
unsigned long phys = ; //0x40000000-0x80000000 -> 0x40000000-0x80000000
for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
} //0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
}
//0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x0; va < 0x10000000; va += 0x100000) {
phys = va + 0x70000000;
addr[va >> ] = phys | ;
} } void memcpy(unsigned char *dest, unsigned char *src, unsigned int len)
{
int i = ;
for(i = ; i < len; i++) {
dest[i] = src[i];
}
} __asm__( /*异常向量表*/
"vector: \n"
" b reset\n"
" b und\n"
" b swi\n"
" b pre_abt\n"
" b data_abt\n"
" .word 0x0\n"
" b irq\n"
" b fiq\n"
"reset:\n"
"und:\n"
" mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, =0x47000004\n"
" ldr r2, [r3]\n"
" blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "swi:\n"
" mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}^\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "pre_abt:\n" "data_abt:\n"
" mov sp, #0x47000000\n"
" sub lr, lr, #4\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, =0x47000008\n"
" ldr r2, [r3]\n"
" blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n"
"irq:\n" " mov sp, #0x47000000\n"
" sub lr, lr, #4\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, =0x47000000\n" //跳转到c语言
" ldr r2, [r3]\n"
" blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "fiq:\n" ".global vector_start\n"
"vector_start: \n"
".word vector \n " );
Tiny4412之重力感应器驱动的更多相关文章
- 基于Tiny4412的I2C驱动分析
本文以tiny4412平台上到三轴加速度器为例简单分析了Linux下到i2c驱动编程. http://pan.baidu.com/s/1c0H5vRq
- Tiny4412之按键驱动
一:按键驱动 按键驱动跟之前的LED,蜂鸣器的方法类似:通过底板,核心板我们可以看到按键的电路图: 通过电路图我们可以看出,当按键按下去为低电平,松开为高电平:所以我们要检测XEINT26的状态,通过 ...
- Tiny4412之蜂鸣器驱动与led灯驱动
一:LED驱动编写 要编写LED驱动,首先的知道开发板的构造:开发板分为核心板与底板:编写驱动的第一步就是要看开发板,找到LED灯在开发板上的位置及所对应的名字:第一步就要查看核心板电路图,以及底板电 ...
- 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九-2)
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...
- Tiny4412之串口(Uart)驱动编写
一:tiny4412串口驱动编写 1.串口通信简介 串口通信指串口按位(bit)发送和接收字节,串口通信的概念非常简单,串口按位(bit)发送和接收字节.尽管比按字节(byte)的并行通信慢,但是串口 ...
- tiny4412 --Uboot移植(6) SD卡驱动,启动内核
开发环境:win10 64位 + VMware12 + Ubuntu14.04 32位 工具链:linaro提供的gcc-linaro-6.1.1-2016.08-x86_64_arm-linux-g ...
- X-010 FriendlyARM tiny4412 uboot移植之移植网卡驱动TFTP用起来
<<<<<<<<<<<<<<<<<<<<<<<<< ...
- 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九)
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...
- 基于tiny4412的Linux内核移植 -- eMMC驱动移植(六)
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...
随机推荐
- AngularJS进阶(二十)HTML5实现获取地理位置信息并定位功能
HTML5实现获取地理位置信息并定位功能 注:请点击此处进行充电! 前言 这篇文章主要介绍了HTML5实现获取地理位置信息并定位功能,本文讲解了原生HTML5.百度地图.谷歌地图等三种获取理位置信息并 ...
- Android性能优化典例(二)
1.使用 Maven 依赖方案代替使用导入jar包方案 如果项目中需要用到第三方jar包,常用的做法是去网上下载后然后放入libs文件夹,再添加到项目依赖,不过,在Android Studio已经不推 ...
- OpenGL Shader Key Points (1)
1. Shader起步 1.1. 可编程管线 仅考虑Vertex shader和fragment shader: 1.2. Shader Object 在编译阶段生成,把shader源代码编译成 ...
- Mego(04) - NET简单实现EXCEL导入导出
前言 相信做过信息系统的朋友都会遇到EXCEL导入导出的相关开发,做过不少EXCEL导入导出后总结起来大致有如下几种方式实现: ADO.NET的OldDb或ODBC连接EXCEL使用DataTable ...
- DB2常见问题
15.1实例常见问题和诊断案例 1.实例无法启动问题 db2nodes.cfg文件,主要是为了数据库分区设计的.如果实例无法启动,要检查db2nodes.cfg,看配置是否正常.db2systm实例配 ...
- oracle面试题目总结
阿里巴巴公司DBA笔试题 http://searchdatabase.techtarget.com.cn/tips/2/2535002.shtml 注:以下题目,可根据自己情况挑选题目作答,不必 ...
- ssh优缺点
面试归来 技术面试官叫我谈谈 ssh优缺点 平时用起来倒是挺顺手..但是从来没有系统的总结过..导致很多点会都没有说出来.. 这次我认真总结了一下... 常说的好处 开源 常说的坏处 配置文件过大我就 ...
- Access Treeview树节点代码二
Private Sub Form_Load() '引用C:\windows\system32\MSCOMCTL.OCX,否则提示出错. Dim Rec As New ADODB.Recordset D ...
- JavaScript中对象数组 作业 题目如下
var BaiduUsers = [], WechatUsers = []; var User = function(id, name, phone, gender, age, salary) { t ...
- 发现DELL笔记本一个很弱智的问题
以前用联想的笔记本,最近联想笔记本坏了,用的是公司的DELL笔记本,发现DELL笔记本一个很弱智的问题. 关于禁用触摸板的问题. 起因: 由于要经常写程序,我配置的有有线鼠标,但是打字时经常碰到触摸板 ...