在龙芯1c上使用rt-thread统一标准的spi接口

本文介绍了如何在龙芯1C上使用RT-Thread的统一SPI接口,通过移植和配置,实现多任务环境下的互斥访问。文章详细讲解了SPI总线注册、从设备挂载、配置、收发函数的使用,以及引脚复用的设置,并提供了一个在龙芯1C上连接双路16位AD芯片TM7705的应用示例。
摘要由CSDN通过智能技术生成

在RTT下为什么推荐使用RTT统一标准的SPI接口

在《【龙芯1c库】封装硬件SPI接口和使用示例》http://blog.csdn.net/caogos/article/details/78353988中提到了,龙芯1c的每路SPI有4个片选,在多任务的实时系统中需要注意互斥的问题。龙芯1C库中的SPI接口仅仅是把龙芯1C的SPI硬件相关特别封装成了一个一个的软件接口。而RT-Thread中统一的标准SPI接口刚好解决了互斥的问题。即只要把龙芯1c库中的SPI接口稍加修改,与RTT中统一的标准SPI接口适配好后,就可以实现使用RTT标准SPI接口编程,而不需考虑互斥的问题。下面以函数 rt_spi_transfer()为例来看看RTT是如何实现互斥的。

程序的大概意思是,在SPI收发之前首先获取锁,以此实现互斥。然后判断上一次SPI通信的从设备是否与当前从设备为同一个,对应代码为if (device->bus->owner != device),如果不是,需要调用evice->bus->ops->configure()函数重新配置SPI的时钟频率,极性和相位等,最后才是调用device->bus->ops->xfer()实现具体的SPI收发。

其实,在刚开始接触RTT和龙芯1C时,不用关注这么多细节,我已经把RTT统一的标准的SPI接口移植到龙芯1C上了,只需要知道怎么使用这些接口即可。如果之前在STM32上用过RTT的SPI,那么我告诉你,在龙芯1C上也是一样的。因为是RTT统一的SPI接口和具体的芯片“无关”。下面来看看RTT提供了几个统一的SPI接口,都有什么功能。

RTT统一的标准的SPI接口简介

注册SPI总线

函数原型

/*
 * 初始化并注册龙芯1c的spi总线
 * @SPI SPI总线,比如LS1C_SPI_0, LS1C_SPI_1
 * @spi_bus_name 总线名字
 * @ret 
 */
rt_err_t ls1c_spi_bus_register(rt_uint8_t SPI, const char *spi_bus_name)

函数ls1c_spi_bus_register()调用RTT的统一标准接口rt_spi_bus_register(),实现SPI总线的注册

使用示例

// SPI模块编号
#define LS1C_SPI_0                      (0)
#define LS1C_SPI_1                      (1)

#define LS1C_SPI0_BUS_NAME              ("spi0")

ls1c_spi_bus_register(LS1C_SPI_1, LS1C_SPI0_BUS_NAME);

挂接SPI从设备到SPI总线

函数原型

rt_err_t rt_spi_bus_attach_device(struct rt_spi_device *device,
                                  const char           *name,
                                  const char           *bus_name,
                                  void                 *user_data)

这个直接就是RTT的统一标准接口rt_spi_bus_attach_device()。

使用示例

#define LS1C_SPI0_BUS_NAME              ("spi0")
#define TM7705_SPI_DEVICE_NAME          ("tm7705")

struct rt_spi_device tm7705_spi_device;
static struct ls1c_spi_cs spi_cs;

// 把从设备(tm7705)挂在SPI总线上
spi_cs.cs = LS1C_SPI_CS_1;
result = rt_spi_bus_attach_device(&tm7705_spi_device, 
                                  TM7705_SPI_DEVICE_NAME, 
                                  LS1C_SPI0_BUS_NAME, 
                                  &spi_cs);
if (RT_EOK != result)
{
    rt_kprintf("[%s] attach spi device tm7705 fail.\n", __FUNCTION__);
    return ;
}

注意,这里把片选信息以入参的形式传递给RTT。变量tm7705_spi_device和spi_cs常定义为static类型,我这里把tm7705_spi_device定义为全局变量了,也是可以的。目的是不能把这两个变量作为函数的临时变量,所占的空间不能被自动释放。
片选信息的结构体定义在头文件“bsp\ls1cdev\drivers\drv_spi.h”里,如下

struct ls1c_spi_cs
{
    unsigned char cs;       // LS1C_SPI_CS_0, LS1C_SPI_CS_1, LS1C_SPI_CS_2 or LS1C_SPI_CS_3
};

片选的几个可选值在头文件bsp\ls1cdev\libraries\ls1c_spi.h”中已定义好了,如下

// 片选
#define LS1C_SPI_CS_0                   (0)
#define LS1C_SPI_CS_1                   (1)
#define LS1C_SPI_CS_2                   (2)
#define LS1C_SPI_CS_3                   (3)

注意,这几个片选宏的值不能随意更改,函数ls1c_spi_set_cs()使用这几个值来设置龙芯1C的SPI片选控制寄存器的。实际上也没必要修改这几个宏的值,直接调用即可。

配置SPI

函数原型

t_err_t rt_spi_configure(struct rt_spi_device        *device,
                          struct rt_spi_configuration *cfg)

配置信息的结构体为

/**
 * SPI configuration structure
 */
struct rt_spi_configuration
{
    rt_uint8_t mode;
    rt_uint8_t data_width;
    rt_uint16_t reserved;

    rt_uint32_t max_hz;
};

注意,龙芯1C只关注其中的modemax_hz就可以了。data_widthreserved可以忽略。

使用示例

struct rt_spi_device tm7705_spi_device;
struct rt_spi_configuration cfg;

// 配置SPI
cfg.mode    = RT_SPI_MODE_3;
cfg.max_hz  = 100*1000;
rt_spi_configure(&tm7705_spi_device, &cfg);

几个常用的SPI收发函数

rt_spi_send()

函数原型

rt_inline rt_size_t rt_spi_send(struct rt_spi_device *device,
                                const void           *send_buf,
                                rt_size_t             length)

使用示例

struct rt_spi_device tm7705_spi_device;
const unsigned char send_buf[4] = {0xFF};

rt_spi_send(&tm7705_spi_device, send_buf, 4);

rt_spi_recv()

函数原型

rt_inline rt_size_t rt_spi_recv(struct rt_spi_device *device,
                                void                 *recv_buf,
                                rt_size_t             length)

使用示例

struct rt_spi_device tm7705_spi_device;
Unsigned char recv_buf[4] = {0};

rt_spi_recv(&tm7705_spi_device, recv_buf, 4);

rt_spi_send_then_recv()

函数原型

rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device,
                               const void           *send_buf,
                               rt_size_t             send_length,
                               void                 *recv_buf,
                               rt_size_t             recv_length)

使用示例

struct rt_spi_device tm7705_spi_device;
unsigned char send_buf[1] = {0};
unsigned char recv_buf[2] = {0};

rt_spi_send_then_recv(&tm7705_spi_device, send_buf, 1, recv_buf, 2);

RTT还提供了rt_spi_send_then_send()、rt_spi_transfer()等,具体查看源码,应该很容易看懂的。

设置引脚复用(不是必须的)

可能需要设置引脚复用,引脚复用接口使用头文件“bsp\ls1cdev\libraries\ls1c_pin.h”中的pin_set_remap()即可。例如

// spi复用
#define LS1C_SPI_1_CS_0_GPIO            (49)        // gpio49/spi1_cs0/CAMHSYNC
#define LS1C_SPI_1_CS_1_GPIO            (50)        // gpio50/spi1_cs1/CAMDATA0
#define LS1C_SPI_1_CS_2_GPIO            (51)        // gpio51/spi1_cs2/CAMDATA1
#define LS1C_SPI_1_CS_3_GPIO            (52)        // gpio52/spi1_cs3/CAMDATA2
#define LS1C_SPI_1_MISO_GPIO            (47)        // gpio47/spi1_miso/CAMCLKOUT
#define LS1C_SPI_1_MOSI_GPIO            (48)        // gpio48/spi1_mosi/CAMVSYNC
#define LS1C_SPI_1_CLK_GPIO             (46)        // gpio46/spi1_clk/CAMPCLKIN

// SPI1 CS1
pin_set_remap(LS1C_SPI_1_MISO_GPIO, PIN_REMAP_THIRD);
pin_set_remap(LS1C_SPI_1_MOSI_GPIO, PIN_REMAP_THIRD);
pin_set_remap(LS1C_SPI_1_CLK_GPIO,  PIN_REMAP_THIRD);
pin_set_remap(LS1C_SPI_1_CS_1_GPIO, PIN_REMAP_THIRD);   // cs1

综合应用示例——在龙芯1C上接双路16位AD芯片TM7705

本示例为3d打印机中使用tm7705+NTC热敏电阻实现温度测量的那部分代码,有兴趣的可以移步到

《【龙印】在龙芯1c上用TM7705+NTC热敏电阻实现温度测量》http://blog.csdn.net/caogos/article/details/531266

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值