ADI锁相环LTC6946-2使用(2-基于C语言的SPI实现)

上一章讲了环路滤波器的设计,本章主要对SPI如何实现进行讲解。SPI作为一种常用的控制总线,在嵌入式应用中很常见。ADI的芯片SPI的配置方式都基本相同,对于不同类型的片子,有可能时序会存在少许差异,需要留心手册的详细说明。
查阅LTC6946的手册时,找到SPI读写的时序图如下所示:
ADI锁相环LTC6946-2使用(2-基于C语言的SPI实现)_第1张图片
ADI锁相环LTC6946-2使用(2-基于C语言的SPI实现)_第2张图片
从图中可以看到SPI的读写都是以CS管脚拉低开始的,都是在时钟的上升沿进行数据采样的,可能其他片子会出现读取的时候是在时钟的下降沿,这点需要特别关注。在做控制时,管脚在各个状态下的控制时长需要参考electrical characteristics中的约束:
ADI锁相环LTC6946-2使用(2-基于C语言的SPI实现)_第3张图片
SPI写的过程参考下图,首先写入需要配置寄存器的地址,之后再写入寄存器的配置值:
ADI锁相环LTC6946-2使用(2-基于C语言的SPI实现)_第4张图片
读寄存器也是类似,先写入所要读取的寄存器的地址,之后给出时钟(master模式),再读取SDO的状态:
ADI锁相环LTC6946-2使用(2-基于C语言的SPI实现)_第5张图片
注:我们只以1Byte模式做示例,如果对于多Byte模式有兴趣可以自行学习,或者留言交流。
从图中可以看到,地址位占7bits,功能位占1bit,由功能位指示当前的操作是读寄存器还是写寄存器,也就是说第一个Byte写入便告知了设备,当前的操作是读操作还是写操作,以及操作的寄存器是哪个,之后下一Byte即为读或写的值。读写SPI的C语言程序我这里做了简单的封装,可以参考实现,对SPI读写速率有要求的朋友可以自行设置程序中的延迟,但必须遵循手册里的最小时序要求。本示例程序是在松翰科技的SN8F5702单片机上实现,若需要在其它MCU上实现,则需要修改相应的控制管脚和时延函数。

/**
*  函 数:  SetSckPinValue()
*  功 能:  控制时钟管脚的电平
*  作 者:
*  日 志:  函数创建
*/
void SetSckPinValue(uint8_t val)
{
	if (val > 0)
	{
		P13 = 1; /*管脚拉高*/
	}
	else
	{
		P13 = 0; /*管脚拉低*/
	}
}

/**
*  函 数:  SetMosiPinValue()
*  功 能:  设置SDI管脚的状态
*  作 者:
*  日 志:  函数创建
*/
void SetMosiPinValue(uint8_t val)
{
	if (val > 0)
	{
		P14 = 1; /*管脚拉高*/
	}
	else
	{
		P14 = 0; /*管脚拉低*/
	}
}

/**
*  函 数:  SetCePinValue()
*  功 能:  设置CS管脚的状态
*  作 者:
*  日 志:  函数创建
*/
void SetCePinValue(uint8_t val)
{
	if (val > 0)
	{
		P16 = 1; /*管脚拉高*/
	}
	else
	{
		P16 = 0; /*管脚拉低*/
	}
}

/**
*  函 数:  GetMisoPinValue()
*  功 能:  读取SDO管脚的状态
*  作 者:
*  日 志:  函数创建
*/
uint8_t GetMisoPinValue(void)
{
	uint8_t val = 0xff;
	
	val = P15;
	return val;
}

/**
*  函 数:  Delay10us()
*  功 能:  以10us为单位进行阻塞性延迟
*  作 者:
*  日 志:  函数创建
*/
void Delay10us(uint16_t n)
{
	uint16_t i;
	unsigned char j;
	for (i=0; iSDout
	}
	
	SetCePinValue(1); /*将CS管脚拉高*/
	Delay10us(10);
	
	return (iTemp);
}

/**
*  函 数:  SpiUpdataRegist()
*  功 能:  配置锁相环寄存器
*  作 者:
*  日 志:  函数创建
*/
void SpiUpdateRegist(uint8_t addr, uint8_t value)
{
	uint8_t val = 0;
	
	SetCePinValue(0); /*将CS管脚拉低*/
	
	val = (addr << 1) | DAT_WRIRE;
	SpiWriteD(&val, 1); /*写入需要配置的寄存器地址*/
	
	SpiWriteD(&value, 1); /*更新寄存器*/
	
	SetCePinValue(1); /*将CS管脚拉高*/
	Delay10us(10);
	SetCePinValue(0); /*将CS管脚拉低*/
	Delay10us(10);
	SetCePinValue(1); /*将CS管脚拉高*/
	Delay10us(10);
}

在进行SPI控制的时候,我这里没有直接使用单片的SPI功能,而是直接使用GPIO管脚模拟SPI读写时序完成SPI读写,目的是为了更好的兼容其它芯片,本示例程序已经验证通过,可以直接使用,另外需要注意的是在SPI写的时候,CS的控制要严格按照时序图进行操作,在数据写入完成之后,CS拉高,保持tCSH时长之后必须拉低,PLL芯片才认为该次写入结束。写入数据和读取数据都是MSB的方式。在调试的时候可以使用示波器同时抓取各个管脚上的信号,配合查看读写的情况。
本章SPI的读写就差不多是这样了,有时间了下一章我再补上LTC6946-2的寄存器配置。

你可能感兴趣的:(嵌入式开发,单片机,经验分享,程序人生,软模拟SPI程序,锁相环设计,仿真,应用)