STM32调试TIC12400笔记

工作中需要用到,但是有关这个芯片的参考资料好少,自己写一下调试过程,用的比较模式,

用了正点原子的mini板,芯片是stm32f103RCT,需要知道spi的相关知识,先配置spi,用cubemx,用硬件spi,下面会解释为什么用硬件,不用模拟,芯片的简介就不详细介绍了,用这个的应该大概有了解 

完整工程链接在下面:

通过网盘分享的文件:tic124.rar
链接: https://pan.baidu.com/s/1u_uRkKURefGZlt5EnixgBw 提取码: ff6i 
--来自百度网盘超级会员v7的分享

一、建立通讯

1.tic时序分析 

首先是调通spi通信,和芯片建立联系,这部分需要看手册

先看时序,可以看到起始为低电平(也就是CPOL=0),在第二个沿采样(红色部分),也就是偶数个边沿也是下降沿采样(CPHA=1),spi最重要的两个参数就确定好了

1.1配置cubemx 

接下来就可以配置cubemx了

 cubemx老生常谈的步骤SYS-->RCC-->时钟树-->connectivity

 RCC

时钟树 

 采用软件片选,需要自己添加一路引脚,任选,只要不和你用的其他引脚发生冲突就行,我选的PA2

增加一路串口,用来调试

1.2基础代码 

新建好工程以后,在spi.cl里添加sp读写单字节代码,注意位置,否则改cubemx配置会覆盖代码

/* USER CODE BEGIN 1 */
/*SPI1 读写一个字节数据*/
uint8_t spi1_read_write_byte(uint8_t txdata){
	uint8_t rec_data;
	HAL_SPI_TransmitReceive(&hspi1,&txdata,&rec_data,1,1000);
	return rec_data;
}

/* USER CODE END 1 */

在uart.c里添加重定向函数,用来打印,同样注意位置,如果报错,还需添加头文件stdio.h

/* USER CODE BEGIN 1 */
int fputc(int ch, FILE *f)
{
	/* 发送一个字节数据到串口DEBUG_USART */
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);	
	
	return (ch);
}
/* USER CODE END 1 */

2.读写函数 

接下来是读写格式,用来编写读写函数,发现tic12400这块芯片每次发送32bit,而硬件spi都是8bit或者16bit,我们这里依旧采用板子自带的硬件8位spi,每八位一发,连发四次,凑够32bit,因为自己写时序比较麻烦,所以不用模拟spi

2.1 读写格式分析

写数据到芯片:要写 读写位+寄存器地址+数据+校验位

MOSI:      1  +  reg_addr  +    data     +   PAR

                bit 31  bit[30-25]      bit[24-1]     bit 0

可以看到写也是有返回值的,会返回六位标志位和上一次写入寄存器的值,可以通过接收写函数的返回值,判断数据发送对了

 从芯片读数据:要写 读写位+寄存器地址+don't care+校验位

MOSI:      0  +  reg_addr  +  don't care   +   PAR

                bit 31  bit[30-25]      bit[24-1]          bit 0

读也要写寄存器地址,不关心的位可以任意写,我写的全是0

从上图可以看到是有校验的,需要自己添加奇偶校验位,读手册可知用的是奇校验,所以我自己写了添加校验位的函数

2.2 读写函数代码

可能会需要延时,不需要太精确,用的for循环的

片选的引脚定义在tic12400.h里,注意引脚,我用的PA2;宏定义是寄存器偏移量

tic12400.h

#ifndef _TIC12400_H_
#define _TIC12400_H_

#include "spi.h"
#include "stdio.h"

#define  DEVICE_ID       0x1
#define  INT_STAT        0x2
#define  CRC_reg         0x3
#define  IN_STAT_MISC    0x4
#define  IN_STAT_COMP    0x5
#define  IN_STAT_ADC0    0x6
#define  IN_STAT_ADC1    0x7
#define  CONFIG          0x1A
#define  IN_EN           0x1B
#define  CS_SELECT       0x1C
#define  WC_CFG0         0x1D
#define  WC_CFG1         0x1E
#define  THRES_COMP      0x21
#define  Mode            0x32


#define SPI_CS(x)   do{ x ? \
                              HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); \
                           }while(0) 

void for_delay_us(uint32_t nus);
uint32_t odd_parity(uint32_t num);
uint32_t tic12400write(uint8_t addr,uint32_t data);
uint32_t tic12400read(uint8_t addr);
uint32_t get_data(uint32_t data);

#endif

 tic12400.c

void for_delay_us(uint32_t nus)
{
 uint32_t Delay = nus * 168/4;
 do
 {
		__NOP();
 }
 while (Delay --);
}
uint32_t odd_parity(uint32_t num){
	uint8_t i=0,count=0;
	uint32_t ret=num;
	for(i=0;i<32;i++){
		if(num & 0x1) count++;
		(num)>>=1;
	}
	if(count%2==0){
		ret |=0x1;
	}
	return ret;
}
uint32_t tic12400write(uint8_t addr,uint32_t data){
	uint32_t senddata=0x80000000;//写bit31=1
	uint32_t ret,temp;
	
	senddata|=(addr<<25);//加入六位地址
	senddata|=(data<<1);//24位数据
	senddata=odd_parity(senddata);//添加奇偶校验位
	
	SPI_CS(1);//片选
	SPI_CS(0);
	
	temp=spi1_read_write_byte(senddata>>24);//发送数据,MSB先行,同时会有数据回传,也接收数据
	ret=temp<<24;
	temp=spi1_read_write_byte(senddata>>16);
	ret|=temp<<16;
	temp=spi1_read_write_byte(senddata>>8);
	ret|=temp<<8;
	temp=spi1_read_write_byte(senddata);
	ret|=temp;
	
	SPI_CS(1);
	return ret;
}

uint32_t tic12400read(uint8_t addr){
	uint32_t senddata=0;
	uint32_t ret,temp;
	senddata|=(addr<<25);//加入六位地址
	senddata=odd_parity(senddata);//添加奇偶校验位
	
	SPI_CS(1);
//	for_delay_us(2);
	SPI_CS(0);
//	for_delay_us(2);
	
	temp=spi1_read_write_byte(senddata>>24);//发送数据,MSB先行,同时会有数据回传,也接收数据
	ret=temp<<24;
	temp=spi1_read_write_byte(senddata>>16);
	ret|=temp<<16;
	temp=spi1_read_write_byte(senddata>>8);
	ret|=temp<<8;
	temp=spi1_read_write_byte(senddata);
	ret|=temp;
	ret=odd_parity(ret);//添加奇偶校验位
	
	SPI_CS(1);
	return ret;
}

读写函数都写好之后我们来检测一下是否能与tic12400通信成功

这里需要用到下面这个寄存器

读到的结果会是bit5=1,也就是0x20

还有一点,tic12400所有的寄存器给的都是数据位,也就是相当于读写函数里的bit[1-24]

我们前面写的读函数接收到的是32位数据,所以这里要对数据进行处理,添加数据处理函数

uint32_t get_data(uint32_t data){
		data>>=1;
		data&=0xffffff;
	  return data;
}

这样读出来结果是0x20,如果不做数据处理,读到的结果会是0x40,也是对的,要分清自己的代码读出的结果

 接下来就可以测试通信了,在mian里加入下面的代码,

 打开串口调试助手,可以接收到数据,通信成功,说明读写代码是没有问题的

 至此通信配置完成,确定可可以和tic12400正常通信

2.3 标志位

如果没用通信成功,就要检测下标志位了,接收数据的时候不要调用数据处理函数,直接调用tic12400read,记得转进制,我是按十六进制打印的

对于这些标志位,都是根据翻译我自己的理解,最好还是看翻译,我理解的不对的话欢迎指正

POR:说明有上电复位、硬件复位或软件复位的情况发生

SPI_FAIL:字节长度不够32bit或大于32bit,这位都会置一

PRTY_FAIL:奇偶校验错误,需要注意的是,如果校验错误,那么这一条数据就被丢弃了,传输的数据无效,所以读到的数据不符合预期很正常

SSC:这一位和INT_STAT中的SSC是一样的,如果设置为1,则表示一个或多个开关输入越过阈值。可以读取寄存器的内容IN_STAT_COMP

这个寄存器是Interrupt Status Register,也就是和中断有关的寄存器,用比较模式的话是不用打开中断的,如果检测到开关超过阈值,这个位会变为一

VS_TH:电压超过设定的值

TEMP:有关温度的报警,可能是温度过高温度关闭(不太理解)

这里列举一个不用数据处理函数的例子,固定位置下加入下面的代码

 /* USER CODE BEGIN 2 */    
    uint32_t data=0;	
	
	data=tic12400read(INT_STAT);
	printf("INT_STAT:%x\n",data);
	
	data=tic12400read(DEVICE_ID);
	printf("DEVICE_ID:%x\n",data);
	
	tic12400write(CONFIG,0x0);
	data=tic12400read(CONFIG);
	printf("CONFIG:%x\n",data);
	
	data=tic12400write(IN_EN,0xffffff);//打开所有开关
	printf("IN_EN:%x\n",data);
	data=tic12400read(IN_EN);
	printf("IN_EN:%x\n",data);
	
//	tic12400write(THRES_COMP,0x7ff);
//	data=tic12400read(THRES_COMP);
//	printf("THRES_COMP:%x\n",data);
//	
	tic12400write(CONFIG,0x800);
	data=tic12400read(CONFIG);
	printf("CONFIG:%x\n",data);
	
	data=tic12400read(IN_STAT_COMP);
	data=get_data(data);
	printf("IN_STAT_COMP:%x\n",data);
 /* USER CODE END 2 */

现象如下 

看下第一行,前六位,刚上电,第一次发送数据,上电复位标志位为1

通讯没问题,如果通讯有问题,就要根据上面的标志位判断是什么问题,另外还需要手动读取INT_STAT寄存器,清空标志位,才能正常通信,或者直接断电也行

接下来就是正是配置这个芯片了

二、配置芯片 

1.寄存器

这个芯片有两种模式,ADC模式和比较模式,ADC模式可以读具体的数值;比较模式,输入电压高于阈值则是开,低于阈值是关

因为我要检测开关通断,不需要知道具体的数值,所以比较模式就够用了,这个模式也比较常用

首先来看寄存器,圈出来的五个是和比较模式有关的寄存器

 1.1DEVICE_ID  0x1

 这个芯片可以用来检测通信是否成功,直接调用tic12400read读出的结果是0x40

1.2 INT_STAT  0x2

这个芯片主要用来清空标志位,如果读到的数据有错误(前面标志位介绍了),需要手动读取这个寄存器,清空标志位,否则无法通信 

跟比较模式配置有关的寄存器按照配置顺序介绍 

1.3 CONFIG  0x1A

看名字就知道这是一个配置寄存器,可以配置芯片的很多功能

举几个例子,其他的看手册重点说比较模式用的

bit[4-1]:轮询时间设置

bit 9:是否开启CRC校验

bit 10:是否开启轮询

bit 12:是否开启中断

bit 22:是否开启ADC自检

配置比较模式的话,有两位比较重要bit11和bit0

bit11:配置寄存器的话,要先将bit11写0再配置,除了图片列举的四个可以在bit11=1的时候配置,其他的配置不进去

       当触发器位设置为逻辑1时,正常的设备操作(润湿电流激活和轮询)开始。要停止设备操作并使设备处于空闲状态,请将此位解除断言为0。
       在触发设备正常操作后,如果在任何时候需要重新配置设备设置,则需要微控制器首先将位TRIGGER设置为逻辑0以停止设备操作。一旦重新配置完成,微控制器可以将TRIGGER位设置回逻辑1以重新启动设备操作。如果在没有首先停止设备操作的情况下动态地进行重新配置,则可能报告错误的开关状态并可能发出意外中断。

以下寄存器位是例外,当触发器位设置为逻辑1时可以配置:

•TRIGGER (CONFIG寄存器的第11位)

•CRC_T (CONFIG寄存器的第9位)

•rest (CONFIG寄存器的第0位)

•CCP_CFG1寄存器0h =停止TIC12400的正常操作。

bit 0:软复位

1.4IN_EN  0x1B

24个开关,写1打开,默认全关闭

1.5THRES_COMP  0x21

设置每个开关的阈值,最高可以到4V,默认应该是2V,用比较模式的话,大于这个值是高电平,小于是零(相当于接地)

1.6 Mode  0x32

模式选择,ADC模式和比较模式,默认是比较模式

2.默认配置 

介绍寄存器的时候说了芯片是有默认配置的,下面来看看默认配置,因为要看标志位,都没有做数据处理

main函数添加以下代码

说明只有奇偶校验位,其余位全是零,根据读写格式可知,前六位全零没错

其他寄存器的配置也可以这样读取,需要用哪个就去读

3.比较模式

我要检测的电压是24V,阈值选哪个都不影响,就保持默认了,我一共要检测十路开关,用的是自己的测试板,板子只预留了12个开关,所以IN_EN只打开12个开关

原理图如下

步骤:

        1.CONFIG[11]=0

        2.IN_EN=0xfff

        3.CONFIG=0x800

然后就可以读取要检测的开关状态了

mian中添加以下代码:

	tic12400write(CONFIG,0x0);
	tic12400write(IN_EN,0xfff);
	tic12400write(CONFIG,0x800);
	data=tic12400read(IN_STAT_COMP);
	printf("IN_STAT_COMP:%x\n",data);

 注:我这十二个开关不是接了地就是接了24V供电,悬空的话读到的的值可能不固定

到这比较模式检测开关状态就已经实现了,

tic12400这个芯片可能会出现下面这种情况,可能是时序问题导致的,也可能是接触不良,还不能确定具体问题,等一会再通信就又好了

因为这个芯片用的时候老是会有问题,所以添加了自检代码,因为POR位和SSC位不影响通信,就不用检测,上电检测没问题以后再开始通信

uint8_t check_flag(uint32_t flag){
	if(flag & 0x40000000){
		printf("SPI FAIL,please check spi data bit\n");
		return 1;
	}
	if(flag & 0x20000000){
		printf("PRTY FAIL\n");
		return 1;
	}
//	if(flag & 0x10000000){
//		printf("SSC FAIL\n");
//		return 1;
//	}
	if(flag & 0x8000000){
		printf("VS_TH FAIL\n");
		return 1;
	}
	if(flag & 0x4000000){
		printf("Temperature ERROR\n");
		return 1;
	}
	return 0;
}
uint8_t selfcheck(void){
	uint32_t data=0;	
	data=tic12400read(DEVICE_ID);
	if(check_flag(data)){
		return 0;
	}
	data=get_data(data);
	if(data &0x20){
		printf("communicate success\n");
	}
	return 0;
}

4.复位 

这个芯片又硬复位和软复位 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值