一、SPI
1.基本概念
SPI 是英语 Serial Peripheral interface(串行外设接口) 的缩写,顾名思义就是串行外围设备接口。是 Motorola首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI 是一种高速的,全双工,同步的串行通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
标准SPI采用四线组网方式,如下图:

只有一个主机,主机发起通信,从机默认接收,SCLK时钟信号线、MOSI主出从入、MISO主入从出、CS片选信号线(低电平有效)。要加上拉电阻。
2.时序
SPI的数据传输的时序:要理解SPI的通信时序。需要搞清楚SPI的两个重要概念。时钟极性 (Clock Polarity 简称CPOL)和时钟相位 (Clock Phase 简称CPHA)。注意这两个概念都是跟时钟信号线相关的。
CPOL :规定了时钟信号线在空闲时的状态,CPOL=0表示时钟信号线在空闲时为低电平;CPOL=1表示时钟信号线在空闲是为高电平;
CPHA :与I2C不同,SPI的数据接收方并不是在时钟高或者低电平时采样的,而是在时钟信号处于沿时,至于是在上升沿还是下降沿取决于CPHA。CPHA=0表示是在时钟信号变化的第一个沿时采样,CPHA=1表示是在时钟信号变化的第二个沿时采样。
需要看手册来选择这四种方式。
I.MX6U手册:

单片机定义高位先行;模式分为四种方式。发送的bit位八的整数倍。
3.读写
*SPI是全双工移位通信:主从两侧各有一个移位寄存器。每个时钟沿到来时,主机通过 MOSI 往外"移出"1位,同时从 MISO "移入"1位。也就是------每"写"一位的同时必然"读"到一位。
*写即是读:你往总线"写"一个字节(移出8位),同一过程里也会"读"回从机在MISO上的8位(可能是无效/占位字节)。
*读即是写:你想从从机"读"数据,必须提供时钟,所以主机必须同时"写"出一个占位字节(通常是0xFF或0x00),用这些时钟把从机的数据"移入"。
读取时,需要先给他发一个消息,因为他是同步的,这时会返回所要读取的内容。
二.adxl345
1.作用
三轴加速度传感器,测姿态,通过重力来测量姿态。本质是adc,设置分辨率(最高为13),基准电压。
2.时序图

由第一个图可得,CPOL=1,CPHA=1
3.连接方式

4.读写寄存器
1)0x2E

2)0x31


3)0x2C



4)0x2D

5)保存的位置

三、寄存器
1.时钟


由PLL3(480MHz)产生,经过八分频,时钟频率为60MHz。
2.RXDATA接收寄存器

3.TXDATA发送寄存器

4.CONREG控制寄存器



**注意**
第0位设置必须在其他寄存器设置之前设置
5.CONFIGREG配置寄存器

6.STATREG状态寄存器


四、代码
1.spi.h
cs
#ifndef _SPI_H_
#define _SPI_H_
extern void init_spi3(void);
extern unsigned char spi3_read_write(unsigned char data);
#endif
2.spi.c
cs
#include "spi.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "gpio.h"
void init_spi3(void)
{
IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0);
IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0);
IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0);
IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0);
IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0x10B1);
IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0x10B1);
IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0x10B1);
IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20, 0x10B1);
struct GPIO_Type_t t =
{
.direction = gpio_output,
.defalut_value = 1
};
init_gpio(GPIO1, 20, &t);
ECSPI3->CONREG = 0;
ECSPI3->CONREG |= (7 << 20) | (0x0E << 12) | (2 << 8) | (1 << 4) | (1 << 3) | (1 << 0);
ECSPI3->CONFIGREG = 0;
ECSPI3->CONFIGREG |= (1 << 20) | (1 << 4) | (1 << 0);
// ECSPI3->CONREG |= (1 << 0);
}
unsigned char spi3_read_write(unsigned char data)
{
while((ECSPI3->STATREG & (1 << 0)) == 0);
ECSPI3->TXDATA = data;
while((ECSPI3->STATREG & (1 << 3)) == 0);
return ECSPI3->RXDATA;
}
3.adxl345.h
cs
#ifndef _ADX345_H_
#define _ADX345_H_
extern unsigned char adxl345_read(unsigned char reg_address);
extern void adxl345_write(unsigned char reg_address, unsigned char data);
struct ADXL345_Data
{
short x;
short y;
short z;
float xg;
float yg;
float zg;
};
extern void init_adxl345(void);
extern struct ADXL345_Data adxl345_work(void);
#endif
4.adxl345.c
cs
#include "adxl345.h"
#include "spi.h"
#include "gpio.h"
void adxl345_write(unsigned char reg_address, unsigned char data)
{
write_gpio(GPIO1, 20, 0);
spi3_read_write(reg_address);
spi3_read_write(data);
write_gpio(GPIO1, 20, 1);
}
unsigned char adxl345_read(unsigned char reg_address)
{
unsigned char ret;
write_gpio(GPIO1, 20, 0);
spi3_read_write(reg_address | 0x80); //1000 0000
ret = spi3_read_write(0xFF);
write_gpio(GPIO1, 20, 1);
return ret;
}
void init_adxl345(void)
{
adxl345_write(0x2E, 0x08);
adxl345_write(0x31, 0x0B);
adxl345_write(0x2C, 0x08);
adxl345_write(0x2D, 0x0B);
}
struct ADXL345_Data adxl345_work(void)
{
// unsigned char buffer[6];
// buffer[0] = adxl345_read(0x32);
// buffer[1] = adxl345_read(0x33);
// buffer[2] = adxl345_read(0x34);
// buffer[3] = adxl345_read(0x35);
// buffer[4] = adxl345_read(0x36);
// buffer[5] = adxl345_read(0x37);
// struct ADXL345_Data data;
// data.x = buffer[0] | (buffer[1] << 8);
// data.y = buffer[2] | (buffer[3] << 8);
// data.z = buffer[4] | (buffer[5] << 8);
struct ADXL345_Data ret;
ret.x = adxl345_read(0x32);
ret.x |= adxl345_read(0x33) << 8;
ret.y = adxl345_read(0x34);
ret.y |= adxl345_read(0x35) << 8;
ret.z = adxl345_read(0x36);
ret.z |= adxl345_read(0x37) << 8;
ret.xg = ret.x * 0.0039;
ret.yg = ret.y * 0.0039;
ret.zg = ret.z * 0.0039;
return ret;
}
5.main.c
cs
#include "string.h"
#include "led.h"
#include "beep.h"
#include "MCIMX6Y2.h"
#include "key.h"
#include "interrupt.h"
#include "clock.h"
#include "epit.h"
#include "gpt.h"
#include "delay.h"
#include "uart.h"
#include "stdio.h"
#include "i2c.h"
#include "lm75.h"
#include "adc.h"
#include "spi.h"
#include "adxl345.h"
int main(void)
{
init_clock();
system_interrupt_init();
init_led();
init_beep();
// init_key();
// init_epit1();
init_gpt1();
init_uart1();
init_i2c1();
init_adc1_channle1();
init_spi3();
init_adxl345();
while(1)
{
struct ADXL345_Data t;
t = adxl345_work();
//printf("x = %d, y = %d, z = %d\n", t.x, t.y, t.z);
int i, j, k;
i = t.xg * 10;
j = t.yg * 10;
k = t.zg * 10;
printf("x = %d.%d, y = %d.%d, z = %d.%d\n", i / 10, i % 10, j / 10, j % 10, k / 10, k % 10);
}
return 0;
}
