匹配设备树文件在SPI子系统中有两个地方:在 spi_register_master() 中匹配和在 device register 时通过内核的通知链(notifier_block)来调用设备树匹配相关程序。
在 device register 时,需配置 CONFIG_OF_DYNAMIC 宏以开启动态匹配才能够使用设备树添加设备,该宏在 menuconfig/Device Drivers/Device Tree and Open Firmware support 中开启,如下图:
1. SPI控制器1.1 概述
SPI总线是一种全双工串行同步通讯协议,SPI(Serial Peripheral Interface)串行外围接口能够支持串行数据传输,其包含两个独立的8/16/32位移位寄存器分别用于发送和接收。在SPI传输期间,数据同步发送(串行移出)和接收在(串行移入)。
1.2 SPI控制器支持下面的特征
1) 全双工,表示可以同时发送和接收。
2) 用于发送和接收的8/16/32位移位寄存器。
3) 8位预分频逻辑,由时钟配置寄存器的低八位决定。
4) 3个时钟源,包括PCLK、USBCLK和Epll clock。
5) 支持National Semiconductor Microwire的协议和Motorola的串行外设接口。
6) 两个独立的发送和接收FIFO,each 16 samples deep by 32-bits wide。
7) 支持主模式和从模式。
8) 支持只接收没发送的 *** 作。
9) 发送/接收的最大频率为50MHZ,但在CPHA=1,且从发送模式时,最大频率为20MHz。
1.3 信号描述
S3C6410的SPI控制器和SPI接口的外部设备之间的外部信号有4个接口,这几个接口在SPI禁用的时候可以用作通用的GPIO口。
XspiCLK:
串行时钟信号,用于控制传输数据的时间,可作为输入和输出。
XspiMISO:
在主模式下,主设备通过此引脚获取从设备的输出引脚输出的数据,此时作为输入;在从模式下,主设备通过此引脚输出数据到从设备,此时作为输出。
XspiMOSI:
在主模式下,主设备通过此引脚输出数据给从设备,此时作为输出;在从模式下,主设备通过此引脚接收来之从设备输出的数据,此时作为输入。
XspiCS:
从选择信号,当此引脚为低电平的时候,所有的数据发送/接收顺序被执行。
1.4 SPI的 *** 作
S3C6410的SPI接口在S3C6410和外设之间传输一位串行数据,S3C6410的SPI支持CPU或DMA分别发送或接收FIFO,并且支持同时双向传输数据。SPI有两个通道,分别为TX通道和RX通道,TX通道有一个从TX FIFO传输数据到外设的途径,RX通道有一个从外设接收数据到RX FIFO的途径。
CPU或DMA如果要写数据到FIFO中,就必须先写数据到SPI_TX_DATA寄存器中,这样此寄存器中的内容就会自动移动到发送FIFO中,同样的道理;如果要从接收FIFO中读取数据,CPU或DMA就必须访问寄存器SPI_RX_DATA,紧接着,接收FIFO的数据就会自动移动到SPI_RX_DATA寄存器中。在此结合前面提到的移位寄存器,我们把数据寄存器、FIFO和移位寄存器的关系以图1体现:
1.4.1 *** 作模式
HS_SPI支持主和从这两个 *** 作模式,在主模式中,主设备产生HS_SPICLK并且发送到外设。XspiCS信号用于选择从设备,当其为低电平时指示数据有效,也就是,在开始发送或者接收数据包之前必须先设置XspiCS为低电平。
1.4.2 FIFO访问
S3C6410的SPI支持CPU和DMA来访问FIFO,CPU和DMA访问FIFO数据的大小可以选择8/16/32位。如果选择8位的数据大小,有效的数据位为0位到7位。通过触发用于定义的阈值,CPU对FIFO的访问正常打开和关闭。每个FIFO的触发阈值可以设备为0到64字节中任何一个值。如果采用DMA访问,那么SPI_MODE_CFG寄存器的TxDMAOn或者RxDMAOn位必须置位,DMA访问只支持单传输和4突发式传输,在往TX FIFO发送数据时,DMA请求信号在FIFO满之前一直为高电平。在从RX FIFO接收数据时,只要FIFO非空,DMA请求信号都为高电平。
1.4.3 RX FIFO中的结尾字节
在中断模式下,RX FIFO中采样的数量小于阈值,或是在DMA的4突发式模式下,并且没有额外的数据被接收,这些留下的字节被称为结尾字节。为了从RX FIFO中移走这些字节,需要用到内部定时器和中断信号,基于APB总线时钟,内部时钟的值可以设置到1024个时钟。当此定时器的值变为0时,中断信号发生并且CPU能移走RX FIFO中的这些结尾字节。
1.4.4 数据包数目控制
在主模式下,SPI能够控制接收的数据包数量。如果要接收任何数目的数据包,只需要设置PACKET_CNT_REG寄存器,当接收到的数据包的数量和设置的一样时,SPI停止产生SPICLK,如果要重新装载此功能,需要强制性遵循软件或是硬件复位,其中软件复位能够清除除了特殊功能寄存器之外的所有寄存器,而硬件复位则清除所有的寄存器。
1.4.5 片选控制
XspiCS可以选择为手动控制或是自动控制。对于手动控制模式,需要对从选择信号控制寄存器CS_REG的AUTO_N_MANUAL位清零,此模式的XspiCS电平由此寄存器的NSSOUT位控制;对于自动控制模式,需要对从选择信号控制寄存器CS_REG的AUTO_N_MANUAL位置位,XspiCS电平被自动确定在包与包之前,其非活动期间有NCS_TIME_COUNT的值来决定,此模式下的NSSOUT是无效的,见下图:
1.4.6 SPI传输格式
为了支持不同传输特性的外围设备,S3C6410的SPI支持4种数据传输格式,这是由CPOL和CPHA来决定的,下面先来学习这两个概念。
CPOL:
CPOL(clock polarity)时钟极性控制位指定串行时钟是active high(也就是当SCLK时钟有效的时候为高电平的时候)还是active low(也就是当SCLK时钟有效的时候为低电平的时候),此控制位对传输格式没有重大的影响。CPOL=0时,表示SCLK空闲时候为低电平;CPOL=1时,表示SCLK空闲的时候为高电平
CPHA:
CPHA(clock phase)时钟相位控制位选择两个不同的基础传输格式中的一种,CPHA表示数据采样的时刻,如果数据采样时刻对应是SCLK的第一个跳变沿,则CPHA=0;如果数据采样时刻对应是SCLK的第二个跳变沿,则CPHA=1。
SPI主设备和从设备的时钟相位和极性应该一致,这样,SPI主设备就需要根据从设备的时钟相位和极性这两个特性来确定CPOL和CPHA的值了。在一些情况下,为了允许一个主设备和多个有不同要求的从设备通讯,需要主设备来改变时钟相位和极性的值。
接下来,我们来学习SPI总线规范中CPHA=0和CPHA=1的传输格式
第1个跳变沿:
SCLK的第一个跳变沿,从设备的第一个数据位输入到主设备(也即锁存到主设备,这里的锁存也可以理解为采样)和主设备的第一个数据位输入到从设备(也即锁存到从设备)中。对于一些设备,只要从设备被选择,从设备数据输出引脚输出的数据的第一位是有效的,在这种格式中,在/SS引脚变低后的半个时钟周期就产生第一个跳变沿。SPI控制器部分CPOL=0,CPHA=0的时序图就属于这种情形
第2个跳变沿:
前面一个跳变沿从串行数据输入引脚锁存到主设备和从设备的数据位被移入到对应的移位寄存器的LSB或MSB,这由LSBFE位来决定。
这样前面的两个跳变沿就完成了一个数据位的传输了,也说明了对应于一个跳变沿,发送和接收时同时进行的,而不是一个跳变沿对应发送,另一个跳变沿对应接收。
第3个跳变沿:
SPI主设备的下一位数据从输出引脚输入到从设备的输入引脚,与此同时,从设备的下一位数据从输出引脚输入到主设备的输入引脚,如此循环,此过程继续SCLK的16个跳变沿,可以总结出来的规律是:在跳变沿奇数的时候,数据被锁存到设备中,在跳变沿偶数的时候,数据被移入到移位寄存器中。
这样在16个SCLK的跳变沿之后,之前在SPI主设备数据寄存器中的数据已经为移入到从设备数据寄存器中,而之前从设备数据寄存器中的数据已经移入到主设备的数据寄存器中了。
一些设备在数据输出引脚输出的第一个数据位有效之前需要第一个SCK跳变沿,在第二个跳变沿的时候才同步数据输入到主设备和从设备中,在这种格式中,在8个时钟传输 *** 作周期的开始的时候通过设置CPHA位(CPHA=1)来产生第一个跳变沿。
第1个跳变沿:
在SCK时钟同步延时半个周期后马上产生第一个跳变沿,此时主设备指示从设备发送其第一个数据位到主设备的数据输入引脚,但是此数据位并不是即将要发送的数据字节有效的数据位,S3C6410的SPI控制器的CPOL=0和CPHA=1的时序图如下:
第2个跳变沿
这是主设备和从设备的锁存跳变沿,也就是说在此跳变沿的时候,从设备的第一个数据位输入到主设备(也即锁存到主设备)和主设备的第一个数据位输入到从设备(也即锁存到从设备)中。
第3个跳变沿:
前面一个跳变沿从串行数据输入引脚锁存到主设备和从设备的数据位被移入到对应的移位寄存器的LSB或MSB,这由LSBFE位来决定,到此就完成了一个数据位的传输了。
第4个跳变沿:
SPI主设备的下一位数据从输出引脚输入到从设备的输入引脚,与此同时,从设备的下一位数据从输出引脚输入到主设备的输入引脚,如此循环,此过程继续SCLK的16个跳变沿,可以总结出来的规律是:在跳变沿偶数的时候,数据被锁存到设备中,在跳变沿奇数的时候,数据被移入到移位寄存器中。
这样在16个SCLK的跳变沿之后,之前在SPI主设备数据寄存器中的数据已经为移入到从设备数据寄存器中,而之前从设备数据寄存器中的数据已经移入到主设备的数据寄存器中了。
一、添加驱动1、新增模拟SPI驱动文件(drv_soft_spi.c/h)
参考drv_spi.c/h,编写模拟SPI驱动
2、新增模拟SPI配置文件(soft_spi_config.h)
拷贝 \libraries\HAL_Drivers\config\f4\spi_config.h,重命令为soft_spi_config.h
#ifndef __SOFT_SPI_CONFIG_H__
#define __SOFT_SPI_CONFIG_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
// CS(PG10) SCK(PG12) MISO(PF8) MOSI(PF9)
#ifdef BSP_USING_SOFT_SPI1
#ifndef SOFT_SPI1_BUS_CONFIG
#define SOFT_SPI1_BUS_CONFIG \
{\
.mosi_pin.GPIOx = GPIOF, \
.mosi_pin.GPIO_Pin = GPIO_PIN_9, \
.miso_pin.GPIOx = GPIOF, \
.miso_pin.GPIO_Pin = GPIO_PIN_8, \
.sclk_pin.GPIOx = GPIOG, \
.sclk_pin.GPIO_Pin = GPIO_PIN_12,\
.bus_name = "soft_spi1", \
}
#endif /* SOFT_SPI1_BUS_CONFIG */
#endif /* BSP_USING_SOFT_SPI1 */
#ifdef __cplusplus
}
#endif
#endif /*__SPI_CONFIG_H__ */
二、向工程添加文件
1、修改..\board\Kconfig
新增下内容
menu "Onboard Peripheral Drivers"
...
config BSP_USING_SPI_FLASH
bool "Enable SOFT-SPI FLASH (W25Q64)"
select BSP_USING_SOFT_SPI
select RT_USING_SFUD
select RT_SFUD_USING_SFDP
default n
...
menu "On-chip Peripheral Drivers"
...
menuconfig BSP_USING_SOFT_SPI
bool "Enable SOFT SPI BUS"
default n
select RT_USING_SOFT_SPI
if BSP_USING_SOFT_SPI
config BSP_USING_SOFT_SPI1
bool "Enable SOFT SPI1:CS(PG10) SCK(PG12) MISO(PF8) MOSI(PF9)"
default n
endif
...
2、修改\rt-thread\components\drivers\Kconfig
新增如下内容
config RT_USING_SPI
bool "Using SPI Bus/Device device drivers"
default n
if RT_USING_SPI
...
config RT_USING_SOFT_SPI //新增
bool "Enable SOFT SPI mode"
default n
...
3、修改..\libraries\HAL_Drivers\SConscript
新增如下内容
if GetDepend(['RT_USING_SOFT_SPI']):
src += ['drv_soft_spi.c']
4、修改..\libraries\HAL_Drivers\drv_config.h
新增如下内容
...
#include "f4/soft_spi_config.h"
...
三、使用驱动
1、ENV配置
开启模拟SPI
开启SFUD组件
2、设备初初始化
在spi_flash_init.c中添加如下内容,注册softspi1总线,注册softspi10设备并挂载到softspi1总线上;使能SFUD驱动W25Q64块
#include <rtthread.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include "drv_soft_spi.h"
#if defined(BSP_USING_SPI_FLASH)
static int rt_hw_spi_flash_init(void)
{
__HAL_RCC_GPIOG_CLK_ENABLE()
rt_soft_spi_device_attach("softspi1", "softspi10", GPIOG, GPIO_PIN_10)
if (RT_NULL == rt_sfud_flash_probe("W25Q64", "softspi10"))
{
return -RT_ERROR
}
return RT_EOK
}
INIT_COMPONENT_EXPO
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)