《嵌入式硬件(十九):基于IMX6ULL的SPI操作》

一、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;
}
相关推荐
GalaxySpaceX4 小时前
STM32-音频播放
stm32·嵌入式硬件·音视频
千語萬言-13 小时前
硬件岗位基础知识
单片机·嵌入式硬件
Z22ZHaoGGGG15 小时前
verilog中数据跨时钟处理方法
单片机·嵌入式硬件·fpga开发·自动化
FanXing_zl16 小时前
基于整数MCU的FOC控制定标策略深度解析
单片机·嵌入式硬件·mcu·算法·定点运算·q15
【云轩】17 小时前
AIoT项目芯片选型指南:在性能、功耗与成本的十字路口
嵌入式硬件
三佛科技-1873661339717 小时前
FT8370A/B/C/CD/CP高性能次边同步整流芯片典型电路及管脚定义
stm32·单片机·嵌入式硬件
D.....l17 小时前
STM32学习(MCU控制)(WiFi and MQTT)
stm32·单片机·学习
国科安芯17 小时前
光电传感器领域国产MCU芯片抗辐照技术考量
网络·人工智能·单片机·嵌入式硬件·安全
二进制coder19 小时前
BMC RTC:服务器硬件管理的“时间心脏”与系统协同核心
服务器·单片机·实时音视频