目录
前言
本文总结调试SKYWORKS芯片厂商Si5512时钟芯片时的笔记,基于linux5.10.xxx内核,在arm64架构的SOC上验证;
一、依赖文档、工具
文档名 | 说明 | 下载链接 |
---|---|---|
Si5518/12/10/08 Reference Manual | 参考手册 | 厂家技术支持 |
Si 5512 Data Sheet | 数据手册 | https://www.skyworksinc.com/-/media/SkyWorks/SL/documents/public/data-shorts/si5512-datashort.pdf |
AN1360: Serial Communications and API Programming Guide for Si536x, Si540x, and Si55xx Devices | api使用手册 | https://www.skyworksinc.com/-/media/SkyWorks/SL/documents/public/application-notes/an1360-si55xx-540x-536x-serial-comm-api-prog-guide.pdf |
PC工具
ClockBuilder-Pro-4.13.0.2.exe,简称CBPro用于生成配置时钟芯片的bin文件;
可以从参考文档中找到下载链接;
下载链接 https://www.skyworksinc.com/en/Application-Pages/Clockbuilder-Pro-Software
二、让芯片工作的流程
见api手册章节
步骤解释
1、使用CBPro生成用于可以下载到芯片ram中的配置文件prod_fw.boot.bin和user_config.boot.bin,软件的使用方法参照软件内置的参考工程,具体bin文件配置按照实际硬件设计的时钟输出需求配置后导出以上文件;
2、给芯片上电,并通过SOC拉低芯片的复位脚保持低电平一段时间大约1s后拉高复位引脚,对芯片进行一次复位;
3、SOC使用SIO_TEST命令验证串行通信接口通信链路是否正常,芯片支持I2C和SPI接口,这里以SPI 四线为例;
4、SOC使用SIO_INFO命令获取时钟芯片串行通信时一次支持的传输的数据量大小;
5、SOC使用RESTART命令对时钟芯片进行重启,这里可以理解成软重启;
6、SOC通过HOST_LOAD命令下载prod_fw.boot.bin文件到时钟芯片的ram中;
7、SOC通过HOST_LOAD命令下载user_config.boot.bin文件到时钟芯片的ram中;
8、SOC通过BOOT命令对芯片进行boot,可以理解成使下载到ram中的文件进行配置生效;
9、SOC通过REFERENCE_STATUS命令检查时钟是否锁定;
三、以上步骤的SOC下代码实现
1、配置设备树
根据芯片所连接SOC的spi外设的情况配置设备树节点
c
&spiXXX {
num-cs = <1>; //假设此spi下有一个需要驱动处理的片选设备
cs-gpios = <填写gpio配置>;
status = "okay";
#addres-cells = <1>;
#size-cells = <0>;
spidev0: si5512@0 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <1000000>;
reg = <0>;
};
};
2、设备节点生成
linux5.10.xxx内核驱动会解析设备树匹配后生成设备节点/dev/spidevX.X;
3、设备树中引脚配置
主要对与时钟芯片相连的spi、reset复位脚、cs片选脚进行配置;
4、linux C的应用实现
api文档中是C#实现的,这里写下C代码的实现
4.1、打开初始化spi设备节点
c
struct spi_ioc_transfer transfer;
transfer.bits_per_word = 8;
uint32_t spispeed = 1000000;
uint8_t spimode = 3; //0或者3模式
uint8_t spibits = 8;
char *devicename = "/dev/spidev1.0";
int fd_spi = -1;
//全局命令数组
uint8_t check_for_CTS_request[2] = { 0xD0, 0x00 };
uint8_t sio_test_request[4] = { 0xC0, 0x01, 0xAB, 0xCD };
uint8_t sio_test_response[5] = { 0xD0, 0x00, 0x00, 0x00, 0x00 };
uint8_t sio_info_request[2] = { 0xC0, 0x02 };
uint8_t sio_info_response[6] = { 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t restart_request[3] = { 0xC0, 0xF0, 0x00 };
uint8_t restart_response[2] = { 0xD0, 0x00 };
uint8_t boot_request[2] = { 0xC0, 0x07 };
uint8_t boot_response[2] = { 0xD0, 0x00 };
uint8_t reference_status_request[2] = { 0xC0, 0x16 };
uint8_t reference_status_response[6] = { 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t host_load_command[1024] = { 0xC0, 0x05 };
uint8_t host_load_response[2] = { 0xD0, 0x00 };
uint8_t sysref_request[2] = { 0xC0, 0x22 };
uint8_t sysref_response[3] = { 0xD0, 0x00,0x00 };
uint8_t response[20]={0};
unsigned char buffer[40960]; // 存储文件数据
unsigned char buffer_1k[1024];
const char *file1path = "prod_fw_pps.boot.bin";
const char *file2path = "user_config.boot.bin";
uint8_t spi_init()
{
fd_spi = open(devicename, O_RDWR);
if (fd_spi < 0)
{
printf("Unable to open '%s'", devicename);
return 0;
}
else
{
if (ioctl(fd_spi , SPI_IOC_WR_MODE, &spimode) == -1)
{
printf("can not set spi mode\n");
return 0;
}
if (ioctl(fd_spi , SPI_IOC_RD_MODE, &spimode) == -1)
{
printf("can not get spi mode\n");
return 0;
}
if (ioctl(fd_spi , SPI_IOC_WR_BITS_PER_WORD, &spibits) == -1)
{
printf("can not set bits per word.");
return 0;
}
if (ioctl(fd_spi , SPI_IOC_RD_BITS_PER_WORD, &spi.bits) == -1)
{
printf("can not get bits per word.");
return 0;
}
if (ioctl(fd_spi , SPI_IOC_WR_MAX_SPEED_HZ, &spispeed) == -1)
{
printf("can not set max speed HZ");
return 0;
}
if (ioctl(fd_spi , SPI_IOC_RD_MAX_SPEED_HZ, &spispeed) == -1)
{
printf("can not get max speed HZ");
return 0;
}
}
return 1;
}
4.2、读写通用函数
c
uint8_t send_data[2048]={0};
uint8_t recv_data[2048]={0};
uint8_t spi_stransfer(uint8_t *in,uint32_t len, uint8_t *out)
{
memset(recv_data,0x00,2048);
if (fd_spi >= 0)
{
if(in[0] == 0xC0) //write
{
memcpy(send_data,in,len);
printf("send write data:");
for(uint32_t i=0;i<len;i++)
{
//printf("%02X ",send_data[i]);
}
printf("\n");
transfer.tx_buf = (unsigned long)send_data;
transfer.len = len;
int ret = ioctl(fd_spi , SPI_IOC_MESSAGE(1), &transfer);
if (ret == 1)
{
printf("Error in writing in SPI");
return 0xFF;
}
return 0x00;
}
else //read
{
memcpy(send_data,in,len);
printf("send read data:");
for(uint32_t i=0;i<len;i++)
{
printf("%02X ",send_data[i]);
}
printf("\n");
transfer.tx_buf = (unsigned long)send_data;
transfer.rx_buf = (unsigned long)recv_data;
transfer.len = len;
int ret = ioctl(fd_spi , SPI_IOC_MESSAGE(1), &transfer);
printf("read data ret:");
for(uint32_t i=0;i<len;i++)
{
printf("%02X ",recv_data[i]);
}
printf("\n");
if (ret != 1)
{
memcpy(out,recv_data,len);
return out[1]; // return data alone to driver
}
else
{
printf("Error in read in SPI");
return 0xFF;
}
}
}
else
{
printf("not initialized spi\n");
return 0xFF;
}
}
4.3、check CTS函数
api文档的流程框图中没有这一步,示例代码中有此函数调用
c
void check_for_CTS()
{
printf("check_for_CTS\n");
spi_stransfer(check_for_CTS_request,sizeof(check_for_CTS_request)/sizeof(check_for_CTS_request[0]),response);
printf("ret:%02X,\n",response[1]);
while(response[1]!=0x80)
{
sleep(1);
spi_stransfer(check_for_CTS_request,sizeof(check_for_CTS_request)/sizeof(check_for_CTS_request[0]),response);
printf("ret:%02X,\n",response[1]);
}
}
4.4、SIO_TEST命令函数
c
void SIO_TEST()
{
printf("SIO_TEST\n");
spi_stransfer(sio_test_request,sizeof(sio_test_request)/sizeof(sio_test_request[0]),response);
memset(response,0x00,20);
spi_stransfer(sio_test_response,sizeof(sio_test_response)/sizeof(sio_test_response[0]),response);
printf("ret:%02X,\n",response[1]);
while(response[1]!=0x80)
{
sleep(1);
spi_stransfer(sio_test_response,sizeof(sio_test_response)/sizeof(sio_test_response[0]),response);
printf("ret:%02X,\n",response[1]);
}
}
4.5、SIO_INFO命令函数
c
uint32_t SIO_INFO()
{
printf("SIO_INFO\n");
spi_stransfer(sio_info_request,sizeof(sio_info_request)/sizeof(sio_info_request[0]),response);
memset(response,0x00,20);
spi_stransfer(sio_info_response,sizeof(sio_info_response)/sizeof(sio_info_response[0]),response);
printf("ret:%02X,\n",response[1]);
while(response[1]!=0x80)
{
sleep(1);
spi_stransfer(sio_info_response,sizeof(sio_info_response)/sizeof(sio_info_response[0]),response);
printf("ret:%02X,\n",response[1]);
}
uint32_t CMD_BUFFER_SIZE = (ret[3] << 8) + ret[2];
return CMD_BUFFER_SIZE ;
}
4.6、RESTART命令函数
c
void RESTART()
{
printf("RESTART\n");
spi_stransfer(restart_request,sizeof(restart_request)/sizeof(restart_request[0]),response);
memset(response,0x00,20);
spi_stransfer(restart_response,sizeof(restart_response)/sizeof(restart_response[0]),response);
printf("ret:%02X,\n",response[1]);
while(response[1]!=0x80)
{
sleep(1);
spi_stransfer(restart_response,sizeof(restart_response)/sizeof(restart_response[0]),response);
printf("ret:%02X,\n",response[1]);
}
}
4.7、HOST_LOAD命令函数
c
void HOST_LOAD(const char *filepath, uint32_t CMD_BUFFER_SIZE)
{
FILE *fp;
unit32_t buffer_size =0;
buffer_size = CMD_BUFFER_SIZE;
size_t bytes_read;
int ret = 0;
struct stat st;
memset(buffer,0x00,40960);
memset(buffer_1k,0x00,1024);
// 打开文件
printf("open filename:%s\n",filepath);
fp = fopen(filepath, "rb");
if (fp == NULL) {
perror("Error opening file");
}
//get file len
ret = stat(filepath, &st);
if (ret != 0) {
perror("stat");
}
printf("File size: %ld bytes\n", st.st_size);
//read file
if ( (bytes_read = fread(buffer, 1, st.st_size, fp)) > 0 )
{
printf("read bytes:%ld\r\n",bytes_read);
}
uint32_t i;
for(i =0;i<(bytes_read/(buffer_size-2));i++)
{
printf("part%d\n",i);
memcpy((void *)buffer_1k,&buffer[i*(buffer_size-2)],(buffer_size-2));
//log
for(uint32_t j=0;j<(buffer_size-2);j++)
{
//printf("%02X ",buffer_1k[j]);
}
printf("\n");
//write
host_load_command[0] = 0xC0;
host_load_command[1] = 0x05;
memcpy((void *)(&host_load_command[2]),(void *)buffer_1k,(buffer_size-2));
spi_stransfer(host_load_command,buffer_size,response);
//read
spi_stransfer(host_load_response,sizeof(host_load_response)/sizeof(host_load_response[0]),response);
printf("ret:%02X,\n",response[1]);
while(response[1]!=0x80)
{
sleep(1);
spi_stransfer(host_load_response,sizeof(host_load_response)/sizeof(host_load_response[0]),response);
printf("ret:%02X,\n",response[1]);
}
}
//文件大小不是完整的buffersize-2的整数单独处理
printf("end part%d\n",i);
memcpy((void *)buffer_1k,&buffer[i*(buffer_size-2)],bytes_read%(buffer_size-2));
for(uint32_t j=0;j<bytes_read%1022;j++)
{
//printf("%02X ",buffer_1k[j]);
}
printf("\n");
//write
host_load_command[0] = 0xC0;
host_load_command[1] = 0x05;
memcpy((void *)(&host_load_command[2]),(void *)buffer_1k,bytes_read%(buffer_size-2));
spi_stransfer(host_load_command,bytes_read%(buffer_size-2)+2,response);
//read
spi_stransfer(host_load_response,sizeof(host_load_response)/sizeof(host_load_response[0]),response);
printf("ret:%02X,\n",response[1]);
while(response[1]!=0x80)
{
sleep(1);
spi_stransfer(host_load_response,sizeof(host_load_response)/sizeof(host_load_response[0]),response);
printf("ret:%02X,\n",response[1]);
}
// 关闭文件
fclose(fp);
}
4.8、BOOT命令实现函数
c
void BOOT()
{
printf("BOOT\n");
spi_stransfer(boot_request,sizeof(boot_request)/sizeof(boot_request[0]),response);
memset(response,0x00,20);
spi_stransfer(boot_response,sizeof(boot_response)/sizeof(boot_response[0]),response);
printf("ret:%02X,\n",response[1]);
while(response[1]!=0x80)
{
sleep(1);
spi_stransfer(boot_response,sizeof(boot_response)/sizeof(boot_response[0]),response);
printf("ret:%02X,\n",response[1]);
}
}
4.9、获取锁定状态函数
c
bool REFERENCE_STATUS()
{
printf("REFERENCE_STATUS\n");
spi_stransfer(reference_status_request,sizeof(reference_status_request)/sizeof(reference_status_request[0]),response);
memset(response,0x00,20);
spi_stransfer(reference_status_response,sizeof(reference_status_response)/sizeof(reference_status_response[0]),response);
printf("ret:%02X,\n",response[1]);
while(response[1]!=0x80)
{
if (response[1] == 0x90) {
printf("FWERR triggered. See text under Common Errors.");
}
sleep(1);
printf("again read\n");
spi_stransfer(reference_status_response,sizeof(reference_status_response)/sizeof(reference_status_response[0]),response);
printf("ret:%02X,\n",response[1]);
}
return ( (response[1] == 0x80) & (response[2] == 0x00) & (response[3] == 0) & (response[4] == 0) & (response[5] == 0) );
}
4.10、复位时钟芯片的函数
c
void hardware_reset()
{
//拉低链接时钟芯片的复位脚
sleep(1);
//拉高链接时钟芯片的复位脚
}
4.11、整体设置芯片的函数
c
void config_si5512()
{
uint32_t cmd_buffer_size = 0;
hardware_reset();
check_for_CTS();
SIO_TEST();
cmd_buffer_size = SIO_INFO();
RESTART();
HOST_LOAD(file1path,cmd_buffer_size);
HOST_LOAD(file2path,cmd_buffer_size);
BOOT();
sleep(2);
uint8_t reference_locked = REFERENCE_STATUS();
while (reference_locked == false) {
printf("waiting lock\n");
reference_locked = REFERENCE_STATUS();
}
if(reference_locked==true)
{
printf("clock is locked\n");
}
}