当前位置: 首页 > news >正文

si551x时钟芯片linux下调试总结

目录

    • 前言
    • 一、依赖文档、工具
    • 二、让芯片工作的流程
    • 三、以上步骤的SOC下代码实现

前言

本文总结调试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 Devicesapi使用手册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外设的情况配置设备树节点

&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设备节点

struct spi_ioc_transfer transfer;
transfer.bits_per_word = 8;
uint32_t  spispeed = 1000000uint8_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、读写通用函数

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文档的流程框图中没有这一步,示例代码中有此函数调用

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命令函数

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命令函数

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命令函数

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命令函数

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 lenret = stat(filepath, &st);if (ret != 0) {perror("stat");}printf("File size: %ld bytes\n", st.st_size);//read fileif ( (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));//logfor(uint32_t j=0;j<(buffer_size-2);j++){//printf("%02X ",buffer_1k[j]);}printf("\n");//writehost_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);  //readspi_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");//writehost_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);//readspi_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命令实现函数

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、获取锁定状态函数

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、复位时钟芯片的函数

void hardware_reset()
{//拉低链接时钟芯片的复位脚sleep(1);//拉高链接时钟芯片的复位脚
}

4.11、整体设置芯片的函数

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");}
}

相关文章:

  • 【论文阅读】Adversarial Training Towards Robust Multimedia Recommender System
  • 物流无人机结构与载货设计分析!
  • 无人机上的热成像相机可以单独使用吗?
  • 准确--Notepad++ 实用的插件介绍
  • 定长滑动窗口---初阶篇
  • ​​大疆无人机“指点飞行模式”​​(TapFly)
  • HarmonyOS Next~HarmonyOS应用测试全流程解析:从一级类目上架到二级类目专项测试
  • HarmonyOS运动开发:如何集成百度地图SDK、运动跟随与运动公里数记录
  • 【django.db.utils.OperationalError: unable to open database file】
  • 基于Django汽车数据分析大屏可视化系统项目
  • 基于Node.js的Web爬虫: 使用Axios和Cheerio抓取网页数据
  • 1、RocketMQ 核心架构拆解
  • 蓝桥杯 20. 倍数问题
  • autojs和冰狐智能辅助该怎么选择?
  • 683SJBH基于J2EE的广州旅游管理系统
  • 【Lanqiao】数位翻转
  • 康养休闲旅游行程服务实训室:打造沉浸式康养旅游人才培养新模式
  • 华为云API、SDK是什么意思?有什么区别和联系?
  • RDD的基本概念及创建方式
  • 【swagger的部署和使用】
  • 国内大模型人才大战打响!大厂各出奇招
  • 综艺还有怎样的新可能?挖掘小众文化领域
  • 解放军仪仗分队参加白俄罗斯纪念苏联伟大卫国战争胜利80周年阅兵活动
  • 中俄弘扬正确二战史观:缅怀历史,重拾初心,阻止悲剧重演
  • 河南省平顶山市副市长许红兵主动投案,接受审查调查
  • 遇冰雹天气,西安机场新航站楼成“水帘洞”