1 IMX6ULL SPI控制器
NXP的6ull参考手册第Chapter 20介绍了SPI控制器,Enhanced Configurable SPI (ECSPI) 。
1.1 特点
①、全双工同步串行接口。
②、可配置的主/从模式。
③、四个硬件片选信号,支持多从机。
④、发送和接收都有一个 32x64 的 FIFO。
⑤、片选信号 SS/CS,时钟信号 SCLK 的极性相位(CPOL,CPHA)可配置。
⑥、支持 DMA
⑦、SCK最高可以到输入参考时钟高达60Mhz
1.2 框图
最右边是引脚,SCLK,MISO,MOSI等,上面是外围总线,通过APB总线进行寄存器读写,INTREG,CONREG等等。TXDATA和TXDATA寄存器存放了要发送的数据和接收的收据。
时钟源来自Reference Clock or Low Frequency Clock。可选时钟源如下:这里选用ecspi_clk_root。
① CSCDR2的ECSPI_CLK_SEL位设置为0,选择出PLL3_SW_CLK 进行8分频作为 ECSPI 根时钟源。PLL3_SW_CLK=480MHz,8分频就是60MHz。
② CSCDR2 的 ECSPI_CLK_PODF位再次进行分频,ECSPI_CLK_PODF位设置成0,表示2^0分频,也就是1分频。
③ 最后ECSPI_CLK_ROOT就为60MHz
1.3 时序
CPOL时钟极性 和CPHA时钟相位组合成了4种模式:
CPOL:表示SPI CLK的初始电平(空闲状态时电平),0为低电平,1为高电平
CPHA:表示相位,即第一个还是第二个时钟沿采样数据,0为第一个时钟沿,1为第二个时钟沿
2 IMX6ULL SPI控制器寄存器描述
控制器初始化流程:
CONREG[EN]:复位,0表示复位
CCM开启ECSPI时钟
CONREG[EN]:复位,1表示反选复位
RXDATA寄存器:接收数据寄存器,RR位的状态决定接受数据是否就绪
TXDATA寄存器:发送数据寄存器,实际传输的位数由相应SPI控制寄存器的BURST_LENGTH位来决定。
CONREG寄存器:控制寄存器
EN:使能位,1为使能
SMC:为1表示当数据写入TXFIFO时,立即启动SPI突发;这里使用该模式
CHANNEL_MODE:硬件片选模式选择,bit[7:4]分别表示通道3到通道0,这里采用通道0设定为Master mode.因此bit[7:4]配置成1
POST_DIVIDER:后分频,0到15表示2^n次方分频,比如0就是1分频,15就是2^15分频
PRE_DIVIDER:前分频,0到15表示1到16分频
前面spi clk的时钟源为ECSPI_CLK_ROOT 60MHz,这里我们用6MHz,因此可以设置POST_DIVIDER=0,PRE_DIVIDER=9,表示10分频。
CHANNEL_SELECT:通道选择,也就是硬件片选SS选择,这里选择SS0,通道0
BURST_LENGTH:突发访问长度,这里我们用一次突发8bit, 配置成0x7
CONFIGREG寄存器:配置寄存器
SCLK_PHA:时钟相位,SCLK_PHA[3:0]分别对应通道3~0,设置为0表示第一个时钟沿采集数据,设置成1表示第二个时钟沿采集数据。(同POL组成4种模式)
SCLK_POL:时钟极性,表示时钟初始空闲时的电平,0为低电平,1为高电平。(同PHA组成4种模式)
SS_CTL:硬件片选的wave form select,这个用不上设置成0
SS_POL:硬件片选的极性选择,用不上设置成0
DATA_CTL:数据线空闲时电平状态,我们设置成0表示高电平
SCLK_CTL:时钟线空闲时电平状态,我们设置成0表示低电平(POL设置了时钟初始空闲时的电平为低电平)
HT_LENGTH: HT Mode不用,无需配置
STATREG寄存器:状态寄存器
TE:TXFIFO empty, 为1表示TXFIFO为空,0表示TXFIFO还没空,因此往TXDATA发送数据时,需要先等待TXFIFO为空。
RR: RXFIFO Ready,1表示有数据,0表示数据还没ready.读取RXDATA需要等RXFIFO先ready。
PERIODREG寄存器:采样周期寄存器
SAMPLE_ PERIOD:突发访问时的等待周期,表示等待多少个时钟周期后进行一下次突发访问。我们设置为0x2000。
CSRC: 等待周期的单位,0表示以SPI clk为单位, 1表示以low-frequency reference clk 32.768KHz为单位。
CSD_CTL:硬件片选延时,表示片选后多少个时钟周期才可以进行数据传输。(这里不用,我们用软件片选)
3 IMX6ULL SPI控制器代码编写
void spi_init(ECSPI_Type *base)
{
/* 配置CONREG寄存器
* bit0 : 1 使能ECSPI
* bit3 : 1 当向TXFIFO写入数据以后立即开启SPI突发。
* bit[7:4] : 0001 SPI通道0主模式,根据实际情况选择,
* 开发板上的ICM-20608接在SS0上,所以设置通道0为主模式
* bit[19:18]: 00 选中通道0(其实不需要,因为片选信号我们我们自己控制)
* bit[31:20]: 0x7 突发长度为8个bit。
*/
base->CONREG = 0; /* 先清除控制寄存器 */
base->CONREG |= (1 << 0) | (1 << 3) | (1 << 4) | (7 << 20); /* 配置CONREG寄存器 */
/*
* ECSPI通道0设置,即设置CONFIGREG寄存器
* bit0: 0 通道0 PHA为0
* bit4: 0 通道0 SCLK高电平有效
* bit8: 0 通道0片选信号 当SMC为1的时候此位无效
* bit12: 0 通道0 POL为0
* bit16: 0 通道0 数据线空闲时高电平
* bit20: 0 通道0 时钟线空闲时低电平
*/
base->CONFIGREG = 0; /* 设置通道寄存器 */
/*
* ECSPI通道0设置,设置采样周期
* bit[14:0] : 0X2000 采样等待周期,比如当SPI时钟为10MHz的时候
* 0X2000就等于1/10000 * 0X2000 = 0.8192ms,也就是连续
* 读取数据的时候每次之间间隔0.8ms
* bit15 : 0 采样时钟源为SPI CLK
* bit[21:16]: 0 片选延时,可设置为0~63
*/
base->PERIODREG = 0X2000; /* 设置采样周期寄存器 */
/*
* ECSPI的SPI时钟配置,SPI的时钟源来源于pll3_sw_clk/8=480/8=60MHz
* 通过设置CONREG寄存器的PER_DIVIDER(bit[11:8])和POST_DIVEDER(bit[15:12])来
* 对SPI时钟源分频,获取到我们想要的SPI时钟:
* SPI CLK = (SourceCLK / PER_DIVIDER) / (2^POST_DIVEDER)
* 比如我们现在要设置SPI时钟为6MHz,那么PER_DIVEIDER和POST_DEIVIDER设置如下:
* PER_DIVIDER = 0X9。
* POST_DIVIDER = 0X0。
* SPI CLK = 60000000/(0X9 + 1) = 60000000=6MHz
*/
base->CONREG &= ~((0XF << 12) | (0XF << 8)); /* 清除PER_DIVDER和POST_DIVEDER以前的设置 */
base->CONREG |= (0X9 << 12); /* 设置SPI CLK = 6MHz */
}
/*
* @description : SPI通道0发送/接收一个字节的数据
* @param - base : 要使用的SPI
* @param - txdata : 要发送的数据
* @return : 无
*/
unsigned char spich0_readwrite_byte(ECSPI_Type *base, unsigned char txdata)
{
uint32_t spirxdata = 0;
uint32_t spitxdata = txdata;
/* 选择通道0 */
base->CONREG &= ~(3 << 18);
base->CONREG |= (0 << 18);
while((base->STATREG & (1 << 0)) == 0){} /* 等待发送FIFO为空 */
base->TXDATA = spitxdata;
while((base->STATREG & (1 << 3)) == 0){} /* 等待接收FIFO有数据 */
spirxdata = base->RXDATA;
return spirxdata;
}
标签:分频,控制器,CONREG,SPI,ECSPI,寄存器,IMX6ULL,时钟
From: https://www.cnblogs.com/fuzidage/p/17780599.html