Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
SPI
瑞萨_Renesas
【开发板评测】Renesas RA2L1 开发板之spi测试分析
发布于 2022-10-21 00:52:19 浏览:808
订阅该版
[TOC] # SPI模块介绍 参考`<
>`的章节`<<28. Serial Peripheral Interface (SPI) >>` ## 特征 - 2通道 - 支持全双工和仅发送模式,支持3线制和4线制 - RSPCK极性反转,相位翻转 - MSB和LSB可设置 - 位长可设置为 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32。 - 32位收发缓存,支持双缓存。 - 主模式下,RSPCK可以由PCLKB分频2~4096得到,从模式下RSPCK最大频率为PCLKB4分频。 - 支持模式错误,校验错误,上下溢出错误检测 - 支持四个片选SSL,单主模式 SSLn0~ SSLn3作为输出;多主模式 SSLn0输入,SSLn1~ SSLn3作为输出或者不用;从模式 SSLn0输入,SSLn1~ SSLn3不用。 - SSL有效到RSPCK产生时钟输出可以配置 1 ~ 8 个RSPCK延迟;RSPCK停止产生时钟输出到SSL无效可以配置 1 ~ 8 个RSPCK延迟。 - SSL无效到下次开始操作有效可以配置 1 ~ 8 个RSPCK延迟。 - 可以直接控制SSL极性 - burst可配置 - 支持以下中断源,接收缓冲满,发送缓冲空,检测到错误,SPI空闲,发送完成。 - 以上中断源支持连接到ELC模块 - 支持配置回环模式 - 支持输出引脚CMOS和开漏配置 - 可以STOP模块支持降低功耗 模块框图如下 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/64a201f451a60a528c6b3fa34ad87194.png.webp) ## 引脚 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/9c594a682c6323ddb196a80908930a41.png.webp) ## 寄存器 这里列举下各寄存器的作用,大致了解下功能,实际编程时可以参考手册。 SPCR:控制寄存器,模块模式,中断使能,模块使能等配置。 SSLP:从模式SSL极性配置 SPPCR:引脚回环设置,MOSI空闲时电平设置 SPSR:状态寄存器,可以看手法缓冲区状态,空闲状态,错误状态 SPDR/SPDR_HA/SPDR_BY:数据寄存器,根据 SPDCR.SPBYT, SPDCR.SPBYT的设置可以按照32位,16位,8位方式访问。收发都是访问该寄存器。 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/5712f946783e3c039f9b05894958376d.png.webp) 对于发送直接写寄存器就是写发送缓存 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/395160affe83222f6650c1372aef988d.png.webp) 对于接收要设置SPDCR.SPRDTD用于选择读收还是法缓存 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/fb2627bb0383530b8ec8e1bfcd26dcb8.png.webp) SPBR:波特率计算寄存器 计算公式为 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/740a05c7187ea1cbe6e4aa2fe51a582d.png.webp) 其中PCLK为FPCLKB n为该寄存器的值0~255 N为SPCMD0.BRDV[1:0]即分频值。 SPDCR:数据控制寄存器,设置 SPDR访问的方式,和读 SPDR时是读受还是发缓存。`SPCKD:SPCMD0.SCKDEN=1`时设置 SSLni有效到RSPCK产生时钟延迟RSPCK时钟的个数,从模式要设置为0。 `SSLND:SPCMDn .SLNDEN=1`时设置RSPCK时钟停止到`SSLni`无效延迟`RSPCK`时钟的个数,从模式要设置为0。 `SPND:SPCMD0.SPNDEN=1`时设置`SSLni`无效到下一次有效延迟`RSPCK`时钟的个数,从模式要设置为0。 `SPCR2`:控制寄存器2,校验等设置 `SPCMD0:SPI`的模式,数据位数等设置。 ## 操作 ### 操作模式设置 支持以下模式 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/08d0a4bb35d930223a604326972f8344.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/9c5024ce0ed09f50eee9a69ed417b648.png.webp) ### 引脚设置 PmnPFS.NCODR ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/6f44c193863e2ea6d44743a06b11d959.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/1aa8a293074a4669201510aa3ad1a40a.png.webp) MOSI在空闲时可以配置为以下状态 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/6e7b4e0cc8137101798cfafc4433846e.png.webp) 其他数据格式,`SPI`模式,错误检测中断等参考手册。 ### 软件关键操作 以下是一些关键操作可以参考手册 `PCLKB`时钟 `MSTPCRB`使能`SPI`模块才能访问`SPI`寄存器,默认是不使能的。 设置中断 设置引脚 `SPCR.SPE=0`初始化 `SPI`各寄存器配置 如果使用`DMADTC`配置 使能`SPI` 中断处理 # 添加SPI驱动 ## 安装RA Configuration `https://www2.renesas.cn/kr/en/software-tool/ra-smart-configurator#overview`下下载, ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/654ddb9a6d8317dc1e887f38e4bff77b.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/3cde5899ec18d24256127977a9f21aec.png.webp) 或者`wget https://github.com/renesas/fsp/releases/download/v4.0.0/setup_fsp_v4_0_0_rasc_v2022-07.exe` 下载慢可以通过以下地址加速下载 `https://gh.api.99988866.xyz/` 下载后点击安装 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/c8a14a131acb45482d13ace3c7c35955.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/16306db816e62f98e6214cfa4ccb547d.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/fc916c90307076a28887b5ef7eadbb92.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/18652a9c52cb51ecfc81049227cb9365.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/892f446a73d05088978a54cbf14d30d8.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/693893a9dced3c382efdba6a3cbf7951.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/103693926ad9b73463eed13f8f1d8b1d.png.webp) ## 添加SPI代码 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/b309a56f161778f5582156be317e5b36.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/0d60296f8f983599cda7e2bd2618c43e.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/125f2d3ed232ce3f3721319cf2ea1d54.png.webp) `SCI0`和`SPI0`引脚重复,不使用`SCI0`,使用`SPI0` ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/b6487726b7c5cf0e2abd0525ee264912.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/7e11cd291289d9f78967793af64ddd54.png.webp) 添加如下SCI0的中断 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/88afa4db36cf1d5ca95177d08fcdbdfe.png.webp) 名字分别为 `spi_eri_isr,spi_rxi_isr,spi_tei_isr,sppi_txi_isr`不添加`idle`中断 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/a2c3718e195b75083c3f599ece1b9162.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/d9b5b39b9602db42674279c050af5431.png.webp) 设置属性,如下 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/bd012072469e94a02a1dd360e0cdcff9.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/f8b447de8ffce7148a06140a6c156f4d.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/ae1f556718ce1653f92ba8332a9b12ce.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/4d36293639486fc0788f3ca2200bd3bd.png.webp) 添加的代码如下 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221021/9bddd39f9a154bba26e3173724ca3222.png.webp) 驱动代码位于 `rt-thread\bsp\renesas\libraries\HAL_Drivers\drv_spi.c和drv_spi.h` 添加到工程`Drivers`目录下。 `rtconfig.h`中添加 `#define RT_USING_SPI` `bsp_mcu_family_cfg.h`注释掉`#include "bsp_mcu_device_pn_cfg.h"` `bsp_cfg.h`中注释掉`#include "board_cfg.h"` `r_spi.c`中实现了中断服务函数 ``` void spi_rxi_isr(void); void spi_txi_isr(void); void spi_tei_isr(void); void spi_eri_isr(void); ``` 与`vector_data.c`和`vector_data.h`中对应。如果编译有错误可以看下这里名字是否对应。 `drv_spi.c`中`spi0_callback`改为`spi_callback` 编译还提示`rt_spi_bus_attach_device`找不到。 将`\rt-thread\components\drivers\spi`下的 `spi_core.c` `spi_dev.c` `drv_spi.c`添加到 工程`Drivers`下 ## 配置 `rtconfig.h`中 添加宏 `#define RT_USING_SPI` `#define BSP_USING_SPI0` `#define RT_USING_DEVICE_OPS` 必须要否则 `rt_spi_bus_device_init`中 ``` #ifdef RT_USING_DEVICE_OPS device->ops = &spi_bus_ops; #else ``` 不会执行 `rt_spi_configure`时会调用`device->bus->ops->configure(device, &device->config);`空函数指针导致`hardfault`。 编译OK 运行输入`list device`就可以看到由`spi0`的设备了。 ``` msh >list device device type ref count -------- -------------------- ---------- spi0 SPI Bus 0 uart9 Character Device 2 pin Pin Device 0 msh > ``` # SPI驱动的使用 参考`https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/spi/spi` 挂载`SPI`设备 `drv_spi.c中rt_hw_spi_device_attach`调用`rt_spi_bus_attach_device` 配置`SPI`设备 `rt_spi_configure` 其他接口参考网页文档 函数 描述 `rt_device_find()`根据 SPI 设备名称查找设备获取设备句柄 `rt_spi_transfer_message()`自定义传输数据 `rt_spi_transfer()`传输一次数据 `rt_spi_send()`发送一次数据 `rt_spi_recv()`接受一次数据 `rt_spi_send_then_send()`连续两次发送 `rt_spi_send_then_recv()`先发送后接收 # SPI驱动分析 初始化过程 定义了`RT_USING_SPI`时 `drv_spi.c`中 `INIT_BOARD_EXPORT(ra_hw_spi_init);` 展开就是 `__attribute__((used)) const init_fn_t __rt_init_ra_hw_spi_init __attribute__((section(x)))(.rti_fn.1) = fn` 也就是定义了`typedef int (*init_fn_t)(void);`函数指针类型的变量 `__rt_init_ra_hw_spi_init`其值就是函数`ra_hw_spi_init`,变量放在了`.rti_fn.1`段。 类似的以下分别定义了连个变量 ``` static int rti_board_start(void) { return 0; } INIT_EXPORT(rti_board_start, "0.end"); static int rti_board_end(void) { return 0; } INIT_EXPORT(rti_board_end, "1.end"); const init_fn_t __rt_init_rti_board_start __attribute__((section(.rti_fn.0.end))) = rti_board_start const init_fn_t __rt_init_rti_board_end __attribute__((section(.rti_fn.1.end))) = rti_board_end ``` 上面定义的`__rt_init_ra_hw_spi_init`位于段`.rti_fn.1` 所以位于段`.rti_fn.0.end`和段`.rti_fn.1.end`之间(按照字母顺序排列)。 `rt_components_board_init`函数中 ``` for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++) { (*fn_ptr)(); } ``` 就是遍历上述定义的两个变量之间,从`__rt_init_rti_board_start`开始找到`__rt_init_rti_board_end`结束 中间就会找到`__rt_init_ra_hw_spi_init`调用其值指向的函数即调用`ra_hw_spi_init` 调用过程如下 ``` rtthread_startup-> rt_hw_board_init-> rt_components_board_init-> ra_hw_spi_init-> rt_spi_bus_register-> ``` 互斥量 其中`rt_spi_bus_register`时会创建互斥量 `rt_mutex_init(&(bus->lock), name, RT_IPC_FLAG_PRIO);` `rt_spi_send_then_recv`等接口中 `rt_mutex_take`会使用。 `cs`引脚 `ra_hw_spi_configure`时`spi_dev->cs_pin = (rt_uint32_t)device->parent.user_data;`会用到 所以`rt_spi_bus_attach_device(&spi_dev,"spi00", "spi0", (void*)spi_cs);`注意这里`spi_cs`前不要加`&`不是传其地址,而是就是传其值,只不过强制转换为(void*). `(rt_uint32_t)device->parent.user_data`用的时候还是会强制转为`(rt_uint32_t)`。 顺便提一下`pin`驱动 `drv_pgio.c`中 `const static struct rt_pin_ops _ra_pin_ops`实现了`io`操作接口。 比如`ra_pin_write` 最终是调用`R_BSP_PinWrite` 通过`bsp_io_port_pin_t`可以看到 我们`spi0`使用的是`p103`所以对应的`pin`号是 ``` BSP_IO_PORT_10_PIN_03 = 0x0A03, ///< IO port 10 pin 3 ``` `spi`底层配置 ``` rt_spi_configure-> device->bus->ops->configure(device, &device->config);-> ra_hw_spi_configure-> R_SPI_Open ``` 进行相应的底层初始化 其中`ra_hw_spi_configure`在 ``` rt_err_t err = rt_spi_bus_register(&spi_config[spi_index].bus, spi_handle[spi_index].bus_name, &ra_spi_ops); ``` 时注册 ``` static const struct rt_spi_ops ra_spi_ops = { .configure = ra_hw_spi_configure, .xfer = ra_spixfer, }; ``` 中注册的 此时可以看到`spi0`总线和`spi00`设备 ``` msh >list device device type ref count -------- -------------------- ---------- spi00 SPI Device 0 spi0 SPI Bus 0 uart9 Character Device 2 pin Pin Device 0 msh > ``` # 回环测试 将P100 J2-16和P101 J2-15短接在一起,也就是SPI0的MISO和MOSI短接在一起。 测试代码如下 `hal_entry.c` ``` /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-10-10 Sherman first version */ #include
#include "hal_data.h" #include
#include
#define LED1_PIN "P502" /* Onboard LED pins */ #define USER_INPUT "P004" void hal_entry(void) { rt_kprintf("\nHello RT-Thread!\n"); rt_uint32_t led1_pin = rt_pin_get(LED1_PIN); uint8_t sendbuf[6]={0,1,2,3,4,5}; uint8_t readbuf[6]={0,0,0,0,0,0}; rt_err_t res; static struct rt_spi_device spi_dev; static rt_uint32_t spi_cs = BSP_IO_PORT_10_PIN_03; res = rt_spi_bus_attach_device(&spi_dev,"spi00", "spi0", (void*)spi_cs); if (res != RT_EOK) { rt_kprintf("rt_spi_bus_attach_device!\r\n"); } else { rt_pin_mode(spi_cs, PIN_MODE_OUTPUT); rt_pin_write(spi_cs, PIN_HIGH); struct rt_spi_configuration cfg; cfg.data_width = 8; cfg.max_hz = 12000000; cfg.mode = RT_SPI_MODE_1 | RT_SPI_MSB; spi_dev.bus->owner = &spi_dev; rt_spi_configure(&spi_dev,&cfg); rt_kprintf("spi0 send:\r\n"); for(int i=0;i
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
qinyunti
这家伙很懒,什么也没写!
文章
30
回答
1
被采纳
0
关注TA
发私信
相关文章
1
BBB的SPI驱动
2
求个SPI上挂两个或多个设备的使用例子
3
SPI设备有个bug
4
spi flash 的fatfs使用一段时间后读写文件出现故障
5
SPI驱动
6
请教rt_spi_configure函数理解
7
SPI FLASH挂载的问题
8
SPI-FLASH 文件系统 SPIFFS
9
求助一个完整的 spi flash 驱动
10
关于同时使用文件系统与SPI FLASH的问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
2
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部