si551x时钟芯片linux下调试笔记

目录

前言

本文总结调试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");
	}
}
相关推荐
worthsen13 分钟前
Linux 服务管理 service systemd systemctl
linux·运维
Xiezequan1 小时前
C语言实现跨主机通讯
linux
巴拉特好队友1 小时前
找到一个linux静态库动态库的好资料.3
linux·运维·服务器
Hacker_Fuchen2 小时前
linux 中 Vi 和 Vim 的使用
linux·运维·vim
努力的小T2 小时前
Debian操作系统相对于Ubuntu有什么优势吗?
linux·运维·服务器·ubuntu·centos·云计算·debian
毒丐2 小时前
Debian系软件管理工具命令大全
linux·运维·debian
陈序缘3 小时前
Ubuntu下PyTorch开发环境配置
linux·pytorch·ubuntu·职场和发展
姜豆豆耶3 小时前
kettle经验篇:Pentaho Repository 类型资源库卡顿问题
linux·运维·华为云·etl
7yewh3 小时前
Bluetooth 蓝牙协议 技术原理
arm开发·驱动开发·硬件工程·信息与通信·蓝牙·基带工程·bluetooth
LaoZhangGong1233 小时前
Linux第99步_Linux之点亮LCD
linux·stm32mp157·modetest