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");
	}
}
相关推荐
KING-WU5123 小时前
Linux GDB 调试实战指南:从编译到断点调试
linux·运维·服务器
Lucis__3 小时前
深入理解程序链接与加载—从动静态链接到库加载
linux·elf·链接·程序·动静态库
影视飓风TIM3 小时前
Linux 进程信号原理与剖析
linux·运维·服务器
缘友一世3 小时前
开源 Linux截图工具闪构(SnapForge)
linux·运维·ubuntu·开源·截图
硅基手札4 小时前
【I2C 技术系列 05】I2C 多主仲裁与时钟同步
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
硅基手札4 小时前
【I2C 技术系列 01】I2C 电气特性与物理层
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
朱包林4 小时前
iTerm2终端配置指南
linux·javascript·python·云原生·容器·kubernetes·云计算
祖力555 小时前
Linux系统移植、烧录与环境的搭建
linux·运维·服务器
张小姐的猫5 小时前
【Linux】网络编程 —— 多路转接:epoll
linux·运维·网络
宋明河6 小时前
五种 IO 模型与 select、poll、epoll 对比
linux