SPI从原理到应用

1.简介

SPI(Serial Peripheral Interface)是一种同步串行通信协议,用于在微控制器、传感器、存储器和其他外围设备之间进行数据交换

SPI协议使用多路单向通信方式,其中包括一个主设备(通常为微控制器或主机)和一个或多个从设备(从器件)。主设备通过控制时钟信号(clk以及数据输入输出线(MISO、MOSI片选线(CS与从设备进行通信。

SPI通信基于全双工传输模式,主设备和从设备之间可以同时发送和接收数据。通信过程由主设备发起,其通过选择特定的片选线来选中从设备。数据交换通过时钟信号同步进行,主设备控制时钟的频率和极性。主设备通过MOSI(主设备输出、从设备输入)线将数据传输到从设备,从设备通过MISO(从设备输出、主设备输入)线将响应数据传输回主设备。

2.SPI传输流程

  1. 主设备选择从设备:主设备通过将片选线(SS/CS)拉低来选择要与之通信的从设备。片选线一般连接到多个从设备,通过只选中其中一个从设备与之通信。

  2. 传输数据:主设备产生时钟信号,并通过主设备输出(MOSI)线将数据发送到从设备,从设备使用从设备输出(MISO)线将响应数据返回给主设备。

  3. 时钟信号同步:主设备通过时钟信号来同步数据传输。时钟信号的频率和极性由主设备控制。根据SPI协议的配置,数据可以在时钟的上升沿或下降沿进行采样和传输。

  4. 数据传输顺序:数据在每个时钟周期内进行位传输,通常是最高位(MSB)优先。主设备和从设备在每个时钟周期传输一个位,直到完成完整的数据传输。

  5. 循环传输:SPI通信往往是循环传输(full duplex),主设备和从设备可以同时发送和接收数据。主设备发送数据的同时,从设备也可以将响应数据发送给主设备。

  6. 传输结束:当数据传输完成后,主设备通过拉高片选线来通知从设备传输结束。

3.gpio模拟spi

#include <stdio.h>
#include <stdint.h>

// 定义GPIO引脚的寄存器地址(示例)
#define GPIO_MOSI    *((volatile uint32_t*) 0x40020000)  // MOSI引脚数据寄存器
#define GPIO_MISO    *((volatile uint32_t*) 0x40020004)  // MISO引脚数据寄存器
#define GPIO_CLOCK   *((volatile uint32_t*) 0x40020008)  // 时钟引脚数据寄存器
#define GPIO_CS      *((volatile uint32_t*) 0x4002000C)  // 片选引脚数据寄存器

void spi_init() 
{
    // 初始化SPI相关GPIO引脚及其他配置
    // 例如,设置引脚方向、片选寄存器的初始状态等

    // 将MOSI和时钟引脚设置为输出模式
    GPIO_MOSI |= (1 << 0);
    GPIO_CLOCK |= (1 << 0);
    // 将MISO引脚设置为输入模式
    GPIO_MISO &= ~(1 << 0);
    // 将片选引脚设置为输出模式
    GPIO_CS |= (1 << 0);
}

void spi_transfer(uint8_t *tx_buffer, uint8_t *rx_buffer, int length) 
{
    int i, j;
    
    for (i = 0; i < length; i++) 
   {
        // 片选使能
        GPIO_CS &= ~(1 << 0);
        
        for (j = 7; j >= 0; j--) 
        {
            // 发送位数据
            GPIO_MOSI = (tx_buffer[i] >> j) & 0x01;
            
            // 上升沿触发时钟信号
            GPIO_CLOCK |= (1 << 0);
            
            // 接收位数据
            rx_buffer[i] |= (GPIO_MISO & 0x01) << j;
            
            // 下降沿触发时钟信号
            GPIO_CLOCK &= ~(1 << 0);
        }
        
        // 片选禁用
        GPIO_CS |= (1 << 0);
    }
}

int main() 
{
    uint8_t tx_buffer[4] = {0x12, 0x34, 0x56, 0x78};
    uint8_t rx_buffer[4] = {0};

    spi_init();  // 初始化SPI模拟

    spi_transfer(tx_buffer, rx_buffer, sizeof(tx_buffer));  // 进行数据传输

    // 打印接收到的数据
    for (int i = 0; i < sizeof(rx_buffer); i++) 
    {
        printf("接收到的数据[%d] = 0x%02X\n", i, rx_buffer[i]);
    }

    return 0;
}

4.linux应用层spi驱动

/**
  ******************************************************************************
  * @file    spifpdriver.c
  * @author  cj
  * @version V1.0
  * @date    2019/7
  * @brief
  ******************************************************************************
  * @attention spi应用层驱动
  ******************************************************************************
  */

#include "spiFPdriver.h"
#include "gpio.h"
#include "board.h"
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <string.h>

#ifdef SPI_FINGER_PRINT

void SPI_SSEL(int val)
{
    spi_control(g_board.fd_gpio, 0, val);
}

void SPI_FastRead(const uint8_t adress, uint8_t *buf, const int len)
{
    int bufSize = 6144;
    int readIndex = 0;
    uint8_t tx[6144] = {0};
    memset(tx, adress, 6144);
    uint8_t rx[6144] = {0};
    while(1)
    {
        int cnt = ((len - readIndex) > bufSize) ? bufSize : (len - readIndex);
        struct spi_ioc_transfer tr =
        {
            .tx_buf = (unsigned long)tx,    //发送缓存区
            .rx_buf = (unsigned long)rx,    //接收缓存区
            .len = (unsigned int)cnt,
            .delay_usecs = 0,               //发送时间间隔
            .speed_hz = 12000000,           //总线速率
            .bits_per_word = 8,             //收发的一个字的二进制位数
        };

        if(ioctl(g_board.fd_spi, SPI_IOC_MESSAGE(1), &tr) < 1)
        {
            qDebug("SPI_FastRead error\n");
            break;
        }

        for (int i = 0; i < cnt; i ++)
        {
            if (rx[i] != 255)
            {
                *buf++ = rx[i];
                readIndex ++;
            }
        }

        if(readIndex == len)
        {
            break;
        }
    }
}

uint8_t SPI_ReadWrite(uint8_t address)
{
    uint8_t tx[1] = {address};
    uint8_t rx[1] = {0};
    struct spi_ioc_transfer tr =
    {
        .tx_buf = (unsigned long)tx,    //发送缓存区
                .rx_buf = (unsigned long)rx,    //接收缓存区
                .len = 1,
                .delay_usecs = 0,               //发送时间间隔
                .speed_hz = 12000000,           //总线速率
                .bits_per_word = 8,             //收发的一个字的二进制位数
    };
    if(ioctl(g_board.fd_spi, SPI_IOC_MESSAGE(1), &tr) < 1)
    {
        qDebug("SPI_ReadWrite error\n");
    }

    return rx[0];
}

static void GPIO_InitSet()
{
    SPI_SSEL(0);
    SPI_ReadWrite(0x4a);
    SPI_ReadWrite(0x04);
    SPI_SSEL(1);

    /* fix a leakage problem */
    SPI_SSEL(0);
    SPI_ReadWrite(0x4F);
    SPI_ReadWrite(0x01);
    SPI_SSEL(1);

    SPI_SSEL(1);
    SPI_SSEL(0);
    SPI_SSEL(1);
}

void SPIFP_driver_Init(void)
{
    /* spi init */
    g_board.fd_spi = open("/dev/spidev0.0", O_RDWR);
    if(g_board.fd_spi < 0)
    {
        printf("bsp_init():can't open spidev0.0\n");
    }

    /* gpio init */
    g_board.fd_gpio = open("/dev/gpio_ctl", O_RDWR);
    if(g_board.fd_gpio < 0)
    {
        printf("bsp_init():can't open gpio\n");
    }

    uint8_t mode = SPI_MODE_0;
    uint8_t bits = 8;
    uint32_t speed = 12000000;//max =12MHz

    if(ioctl(g_board.fd_spi, SPI_IOC_WR_MODE, &mode) == -1)
        qDebug("fpDriver_init: can't set spi mode\n");

    if(ioctl(g_board.fd_spi, SPI_IOC_RD_MODE, &mode) == -1)
        qDebug("fpDriver_init: can't get spi mode\n");

    if(ioctl(g_board.fd_spi, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1)
        qDebug("fpDriver_init: can't set bits per word\n");

    if(ioctl(g_board.fd_spi, SPI_IOC_RD_BITS_PER_WORD, &bits) == -1)
        qDebug("fpDriver_init: can't get bits per word\n");

    if(ioctl(g_board.fd_spi, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1)
        qDebug("fpDriver_init: can't set max speed hz\n");

    if(ioctl(g_board.fd_spi, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1)
        qDebug("fpDriver_init: can't get max speed hz\n");

    GPIO_InitSet();
}

#endif

5.liunx驱动层spi.ko

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define SPI_DRIVER_DEV_NAME "spi_driver"

static int spi_driver_ioctl(struct file* filp, unsigned int cmd, unsigned long arg)
{
    struct spi_device* spi = filp->private_data;
    uint8_t buffer[4] = {0};

    switch (cmd) 
   {
        case SPI_DRIVER_READ:
            // 执行SPI读取逻辑
            // 使用spi_sync_transfer()等函数进行读取
            break;
        
        case SPI_DRIVER_WRITE:
            // 执行SPI写入逻辑
            // 使用spi_sync_transfer()等函数进行写入
            break;
        
        default:
            return -EINVAL;
    }

    return 0;
}

static long spi_driver_unlocked_ioctl(struct file* filp, unsigned int cmd, unsigned long arg)
{
    return spi_driver_ioctl(filp, cmd, arg);
}

static const struct file_operations spi_driver_fops = 
{
    .unlocked_ioctl = spi_driver_unlocked_ioctl,
};

static int spi_driver_probe(struct spi_device *spi)
{
    struct device *dev;

    // 创建设备文件
    dev = device_create(spi_driver_class, NULL, spi->dev.dev, NULL, SPI_DRIVER_DEV_NAME);
    if (IS_ERR(dev)) 
    {
        return PTR_ERR(dev);
    }

    dev_set_drvdata(&dev->dev, spi);

    return 0;
}

static int spi_driver_remove(struct spi_device *spi)
{
    struct device *dev = dev_get_drvdata(&spi->dev);
    
    device_remove_file(dev, &dev_attr_data);
    device_destroy(spi_driver_class, spi->dev.dev);

    return 0;
}

static const struct of_device_id spi_driver_of_match[] = 
{
    { .compatible = "your_device_compatible_string" }, // 根据设备兼容字符串进行匹配
    { },
};
MODULE_DEVICE_TABLE(of, spi_driver_of_match);

static struct spi_driver spi_driver = 
{
    .probe = spi_driver_probe,
    .remove = spi_driver_remove,
    .driver = 
    {
        .name = "spi_driver",
        .owner = THIS_MODULE,
        .of_match_table = spi_driver_of_match,
    },
};

static struct class *spi_driver_class;

static int __init spi_driver_init(void)
{
    int ret;

    spi_driver_class = class_create(THIS_MODULE, "spi_driver");
    if (IS_ERR(spi_driver_class)) 
    {
        return PTR_ERR(spi_driver_class);
    }

    ret = spi_register_driver(&spi_driver);
    if (ret < 0)
   {
        class_destroy(spi_driver_class);
        return ret;
    }

    return 0;
}

static void __exit spi_driver_exit(void)
{
    spi_unregister_driver(&spi_driver);
    class_destroy(spi_driver_class);
}

module_init(spi_driver_init);
module_exit(spi_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("SPI Driver");

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
蛋白质是生物体中普遍存在的一类重要生物大分子,由天然氨基酸通过肽键连接而成。它具有复杂的分子结构和特定的生物功能,是表达生物遗传性状的一类主要物质。 蛋白质的结构可分为四级:一级结构是组成蛋白质多肽链的线性氨基酸序列;二级结构是依靠不同氨基酸之间的C=O和N-H基团间的氢键形成的稳定结构,主要为α螺旋和β折叠;三级结构是通过多个二级结构元素在三维空间的排列所形成的一个蛋白质分子的三维结构;四级结构用于描述由不同多肽链(亚基)间相互作用形成具有功能的蛋白质复合物分子。 蛋白质在生物体内具有多种功能,包括提供能量、维持电解质平衡、信息交流、构成人的身体以及免疫等。例如,蛋白质分解可以为人体提供能量,每克蛋白质能产生4千卡的热能;血液里的蛋白质能帮助维持体内的酸碱平衡和血液的渗透压;蛋白质是组成人体器官组织的重要物质,可以修复受损的器官功能,以及维持细胞的生长和更新;蛋白质也是构成多种生理活性的物质,如免疫球蛋白,具有维持机体正常免疫功能的作用。 蛋白质的合成是指生物按照从脱氧核糖核酸(DNA)转录得到的信使核糖核酸(mRNA)上的遗传信息合成蛋白质的过程。这个过程包括氨基酸的活化、多肽链合成的起始、肽链的延长、肽链的终止和释放以及蛋白质合成后的加工修饰等步骤。 蛋白质降解是指食物中的蛋白质经过蛋白质降解酶的作用降解为多肽和氨基酸然后被人体吸收的过程。这个过程在细胞的生理活动中发挥着极其重要的作用,例如将蛋白质降解后成为小分子的氨基酸,并被循环利用;处理错误折叠的蛋白质以及多余组分,使之降解,以防机体产生错误应答。 总的来说,蛋白质是生物体内不可或缺的一类重要物质,对于维持生物体的正常生理功能具有至关重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值