T613通信协议
T613与客户使用的Soc通信方式有两种:
- Uart 方式通信
- I2C 方式通信
下面我们分别介绍一下通信过程中,具体的实现原理和通信细节。
第一部分: Uart 方式通信
帧格式:
帧头 |
Cmd |
Cmd_Val |
X_Val |
Y_Val |
Z_Val |
CheckSum |
帧详解:
UART |
Head |
0x55AA55AA |
4bytes |
Cmd |
命令字 |
1byte |
|
Cmd_Val |
对应命令的值 |
1byte |
|
X_Val |
X方向的角度值 |
2bytes |
|
Y_Val |
Y方向的角度值 |
2bytes |
|
Z_Val |
Z方向的角度值 |
2bytes |
|
CheckSum |
校验位 |
2bytes |
Head:固定4bytes, 0x55AA55AA
Cmd_Val:相应命令字对应的值大小。比如:
Cmd为LT_ON,
Cmd_Val = 0xf2;则LT_ON的时候设置的值为0xf2,
当Command为LT_OFF,
Cmd_Val = 0xf2,那么此时的Func_Val值无效。
X_Val: X方向的实时角度值。
Y_Val: Y方向的实时角度值。
Z_Val: Z方向的实时角度值。
CheckSum: 校验位。
CheckSum = Cmd + Cmd_Val + X_Val + Y_Val + Z_Val
2、命令字
Typedefenum I2C_UART_CMD{
CMD_ZRota_ON = 0, // 0x00开启左右梯形校正
CMD_ZRota_OFF, // 0x01关闭左右梯形校正
CMD_VCali_ON, // 0x02开启上下梯形校正
CMD_VCali_OFF, // 0x03关闭上下梯形校正
CMD_HCali_ON, // 0x04开启画面旋转
CMD_HCali_OFF, // 0x05关闭画面旋转
CMD_DigFocus_ON, // 0x06开启数字校正
CMD_DigFocus_OFF, // 0x07关闭数字校正
CMD_UnifoBri_ON, // 0x08开启亮度校正
CMD_UnifoBri_OFF, // 0x09关闭亮度校正
CMD_HLinear_ON, // 0x0a开启水平方向线性校正
CMD_HLinear_OFF, // 0x0b关闭水平方向线性校正
CMD_VLinear_ON, // 0x0c开启垂直方向线性校正
CMD_VLinear_OFF, // 0x0d关闭垂直方向线性校正
//陀螺仪原点参考位置选取
CMD_CaliLoca, // 0x0e选取参考位置,此时将XYZ置零
CMD_Rectify_ON, // 0x0f开启自动校正,APP自动更新
CMD_Rectify_OFF, // 0x10关闭自动校正,APP不更新
CMD_Reset, // 0x11复位APP所有设定的值到初始态
CMD_Raspberry, // 0x12 切换树莓派控制
//四点位置校正
//当FPCORR打开时,后面的四点坐标数据才会有效,否则无效
CMD_FPCorr_ON, // 0x13开启四点校正
CMD_FPCorr_OFF, // 0x14关闭四点校正
CMD_CorrA_PX, // 0x15 A点校正X方向值
CMD_CorrA_PY, // 0x16 A点校正Y方向值
CMD_CorrB_PX, // 0x17 B点校正X方向值
CMD_CorrB_PY, // 0x18 B点校正Y方向值
CMD_CorrC_PX, // 0x19 C点校正X方向值
CMD_CorrC_PY, // 0x1a C点校正Y方向值
CMD_CorrD_PX, // 0x1b D点校正X方向值
CMD_CorrD_PY, // 0x1c D点校正Y方向值
CMD_Deflt_Val, // 0x1d 恢复四点初始值
CMD_ReturnBefore, // 0x1e恢复四点校正前的值
CMD_Rotate_ON, // 0x1f打开画面上下翻转180度
CMD_Rotate_OFF, // 0x20关闭画面上下翻转180度
};
注:以上指令中Cmd_Val在
CMD_CaliLoca, // 0x0e选取参考位置,此时将XYZ置零
CMD_Rectify_ON, // 0x0f开启自动校正,APP自动更新
CMD_Rectify_OFF, // 0x10关闭自动校正,APP不更新
CMD_Reset, // 0x11复位APP所有设定的值到初始态
CMD_RASPBERRY, // 0x12切换RASPBERRY和LIGTHING
CMD_Deflt_Val, // 0x1d 恢复四点初始值
CMD_ReturnBefore // 0x1e恢复四点校正前的值
CMD_Rotate_ON, // 0x1f打开画面上下翻转180度
CMD_Rotate_OFF, // 0x20关闭画面上下翻转180度
这些Cmd中值无效(Invalid)。
例CMD_HCali_ON:
55AA55AA 00 45 FF 9B 00 7B FF AB 00 06
Head |
0x55AA55AA |
4bytes |
Cmd |
0x00 |
1byte |
Cmd_Val |
0x45 |
1byte |
X_Val |
0xFF9B |
2bytes |
Y_Val |
0x007B |
2bytes |
Z_Val |
0xFFAB |
2bytes |
CheckSum |
0x0006 |
2bytes |
此时,Command = 0x00,即左右梯形是打开的。故Func_Val = 0x45是有效值(Valid)。
检验位:CheckSum = 0(0x00)+69(0x45)+(-101)(0xFF9B)+123(0x7B)+(-085)(0xFFAB) = 6(0x06)
例CMD_HCali_OFF:
55AA55AA 01 45 FF 9B 00 7B FFAB 00 07
Head |
0x55AA55AA |
4bytes |
Cmd |
0x01 |
1byte |
Cmd_Val |
0x45 |
1byte |
X_Val |
0xFF9B |
2bytes |
Y_Val |
0x007B |
2bytes |
Z_Val |
0xFFAB |
2bytes |
CheckSum |
0x0007 |
2bytes |
此时,Cmd = 0x01,即左右梯形是关闭的。故Func_Val = 0x45是无效值(Invalid)。
检验位:CheckSum = 1(0x01)+69(0x45)+(-101)(0xFF9B)+123(0x7B)+(-085)(0xFFAB) = 7(0x0007)
注:此时虽然Cmd_Val值无效,但是校验时依然要计算。
例CMD_FPCorr_ON:
55AA55AA 13 45 FF 9B 00 7B FFAB 00 19
Head |
0x55AA55AA |
4bytes |
Cmd |
0x13 |
1byte |
Cmd_Val |
0x45 |
1byte |
X_Val |
0xFF9B |
2bytes |
Y_Val |
0x007B |
2bytes |
Z_Val |
0xFFAB |
2bytes |
CheckSum |
0x0019 |
2bytes |
此时,Cmd = 0x13,即四点校正是打开的。接下来的CMD_CorrX_PX/CMD_CorrX_PYcmd才有效(Valid)。
检验位:CheckSum = 19(0x13)+69(0x45)+(-101)(0xFF9B)+123(0x7B)+(-085)(0xFFAB) = 25(0x0019)
例CMD_FPCorr_OFF:
55AA55AA 14 45 FF 9B 00 7B FF AB 00 1A
Head |
0x55AA55AA |
4bytes |
Cmd |
0x14 |
1byte |
Cmd_Val |
0x45 |
1byte |
X_Val |
0xFF9B |
2bytes |
Y_Val |
0x007B |
2bytes |
Z_Val |
0xFFAB |
2bytes |
CheckSum |
0x001A |
2bytes |
此时,Cmd = 0x14,即四点校正是关闭的。接下来的CMD_CorrX_PX/CMD_CorrX_PYcmd无效(Invalid)。
检验位:CheckSum = 20(0x14)+69(0x45)+(-101)(0xFF9B)+123(0x7B)+(-085)(0xFFAB) = 26(0x001a)
注:在我们发送数据的时候,使用者可能会存在一下疑虑?
- 我们通过串口发送数据的时候,数据的具体转换方式是什么?
答:在传输的时候,需要先把数据全部转成unsigned char类型,然后分别切成高八位和低八位,再传输。举个例子:
我们要传输的数据是:
Cmd = 2,
Cmd_Val = -3,
X_Val = -22;
Y_Val = 12;
Z_Val = 4;
那么 CheckSum = 2 + (-3) + (-22) + 12 + 4 = -7
这样的话:数据格式是什么样子的?
由上面的数据格式可以知道,
Cmd = 2, //(unsigned char) 1Byte (8B 0x02)
Cmd_Val = -3, //(signed char) 1Byte (8B 0xFD)
X_Val = -22; //(signed short) 2bytes (16B 0xFFEA)
Y_Val = 12; //(signed short) 2bytes (16B 0x000C)
Z_Val = 4; //(signed short) 2bytes (16B 0x0004)
CheckSum = -7; //(signed short) 2bytes (16B 0xFFF9)
由这些数据我们得到对应的表示格式,那么我们下面写一下伪代码,如下:
//. . . 伪代码部分 . . .
unsigned char arr_uart[14] = 0;
unsigned char cmd_t;
unsigned char cmd_val_t;
unsigned short x_val_t;
unsigned short y_val_t;
unsigned short z_val_t;
unsigned short CheckSum_t;
//数据转换部分
cmd_t = (unsigned char)Cmd;
cmd_val_t = (unsigned char)Cmd_Val;
x_val_t = (unsigned short)X_Val;
y_val_t = (unsigned short)Y_Val;
z_val_t = (unsigned short)Z_Val;
CheckSum_t = (unsigned short)CheckSum;
//帧头数据设置
arr_uart[0] = 0x55;
arr_uart[1] = 0xAA;
arr_uart[2] = 0x55;
arr_uart[3] = 0xAA;
//有效数据放置
arr_uart[4] = cmd_t;
arr_uart[5] = cmd_val_t;
arr_uart[6] = (x_val_t >> 8) & 0xFF; //先传高位
arr_uart[7] = (x_val_t >> 0) & 0xFF; //在传低位
arr_uart[8] = (y_val_t >> 8) & 0xFF; //先传高位
arr_uart[9] = (y_val_t >> 0) & 0xFF; //在传低位
arr_uart[10] = (z_val_t >> 8) & 0xFF; //先传高位
arr_uart[11] = (z_val_t >> 0) & 0xFF; //在传低位
arr_uart[12] = (CheckSum_t >> 8) & 0xFF; //先传高位
arr_uart[13] = (CheckSum _t >> 0) & 0xFF; //在传低位
uart_send(uart_x, arr_uart); //调用uart传输数据函数。
//. . . 伪代码部分 . . .
- 我们通过串口传输数据的时候,Cmd的指令和Cmd_Val,X_Val,Y_Val,Z_Val等这些值要如何下到T613?
答:首先我们需要先下Cmd = CMD_Rectify_ON,如下:
注意这个指令只要发一次即可,后面就不用再发送了!!!
帧头 |
Cmd |
Cmd_Val |
X_Val |
Y_Val |
Z_Val |
CheckSum |
|||||||
55 |
AA |
55 |
AA |
0F |
XX |
XX |
XX |
XX |
XX |
XX |
XX |
XX |
XX |
后面当我们要进行梯形校正的ZRotation的时候,我们就需要下如下命令:
帧头 |
Cmd |
Cmd_Val |
X_Val |
Y_Val |
Z_Val |
CheckSum |
|||||||
55 |
AA |
55 |
AA |
00 |
XX |
XX |
XX |
XX |
XX |
XX |
XX |
XX |
XX |
然后第二次还是要进行ZRotation的时候,我们下的命令如下:
帧头 |
Cmd |
Cmd_Val |
X_Val |
Y_Val |
Z_Val |
CheckSum |
|||||||
55 |
AA |
55 |
AA |
00 |
XX |
XX |
XX |
XX |
XX |
XX |
XX |
XX |
XX |
也就是说,当我们要修改ZRotation的时候,我们的Cmd一直都是下0x00,然后配置对应的值就好了。以此类推,当我们要改XYZ其中任何一个方向校正的时候,我们的命令就下对应的Cmd就好了。
- 客户在使用的时候我们一般都会用PC_UI这个软件来下数据给T613,但是问题是这个是手动下去T613的数据,如何自动呢?
答:这个时候因为我们是用手动去拨动PC_UI上面的进度条,数据也就是我们手动去改的,当我们把PC_UI的工作内容交给前端的Soc的时候,就会变成Soc自动去下载数据,这个时候就能看到我们的现象是自动调整的。
第二部分: I2C 方式通信
- 在T613中存放一帧数据的地址范围:0x10000000~0x1000000E。
- I2C帧数据对应的地址
Head |
0x55AA55AA |
4bytes |
0x10000000~0x10000003 |
Cmd |
命令字 |
1byte |
0x10000004 |
Func_Val |
对应命令的值 |
1byte |
0x10000005 |
X_Val |
X方向的角度值 |
2bytes |
0x10000006~0x10000007 |
Y_Val |
Y方向的角度值 |
2bytes |
0x10000008~0x10000009 |
Z_Val |
Z方向的角度值 |
2bytes |
0x1000000A~0x1000000B |
CheckSum |
校验位 |
2bytes |
0x1000000C~0x1000000D |
I2C_FALG |
I2C标志位 |
1byte |
0x1000000E |
前端Soc和我们的T613通过IIC通信方式如下图:
注:首先声明一下T613的IIC通信速率最高可达1MHz。
3、数据传输
(1) T613 上电将I2C_FLAG 置0x00;
(2) Soc读取I2C_FLAG为0x00,表示可以发送数据给T613,发送完成将I2C_FLAG置0x01(即每帧数据最后一个字节都为0x01)用来告诉T613 ,已经写完一帧数据,可以读取数据;
(3) T613读取完数据,将I2C_FLAG清零,用以告知Soc,可以继续发送数据。
帧头 |
Cmd |
Cmd_Val |
X_Val |
Y_Val |
Z_Val |
CheckSum |
I2C_FLAG |
(4)IIC通信与Uart通信数据格式相同,客户在使用过程中要实现具体的功能请参考Uart部分。
(5)soc与T613的通信时序如下图:
图1 写时序图第一部分
图2 写时序图第二部分
图3 读时序第一部分
图4 读时序第二部分
注:我们采用Single byte write mode,
SlaveAddr = 0x60;
RegAddr : 从0x10000000开始,在传输的过程中我们需要将RegAddr切割成4部分分别发送出去。
伪代码实现如下:
写数据到T613,代码例程:
//现在我们要写数据到T613的0x10000000地址
// . . .伪代码 ,Write data to T613. . .
const unsigned char SLAVE_ADDR_WRITE = 0x60;
unsigned char REG_ADDR1,
REG_ADDR2,
REG_ADDR3,
REG_ADDR4;
unsigned int test_addr = 0x10000000; //寄存器地址
unsigned char test_Wdata = 0x5A; //写入的内容
unsigned char DUMMY = 0x00;
REG_ADDR1 = (test_addr >> 24) & 0xFF; //把要被写入的地址拆分
REG_ADDR2 = (test_addr >> 16) & 0xFF; //把要被写入的地址拆分
REG_ADDR3 = (test_addr >> 8) & 0xFF; //把要被写入的地址拆分
REG_ADDR4 = (test_addr >> 0) & 0xFF; //把要被写入的地址拆分
//Write data to reg
//第一次写入从设备地址和regAddr的前2bytes,最后跟一个byte dummy数据。
IIC_WriteSingleByte(SLAVE_ADDR_WRITE1, REG_ADDR1, REG_ADDR2, &DUMMY);
//第二次写入从设备地址和regAddr的后2bytes,然后写入要写的内容。
IIC_WriteSingleByte(SLAVE_ADDR_WRTIE2, REG_ADDR3, REG_ADDR4, &test_Wdata);
// . . .伪代码 ,Write data to T613. . .
下面我们再举一个从T613寄存器中读数据的例子:
// . . .伪代码 ,Read data from T613. . .
const unsigned char SLAVE_ADDR_READ = 0x60;
unsigned char REG_ADDR1,
REG_ADDR2,
REG_ADDR3,
REG_ADDR4;
unsigned char DUMMY = 0x00;
unsigned int test_addr = 0x10000000; //寄存器地址
unsigned char test_Rdata = 0x00; //读出的内容,存放到这里
REG_ADDR1 = (test_addr >> 24) & 0xFF; //把要被写入的地址拆分
REG_ADDR2 = (test_addr >> 16) & 0xFF; //把要被写入的地址拆分
REG_ADDR3 = (test_addr >> 8) & 0xFF; //把要被写入的地址拆分
REG_ADDR4 = (test_addr >> 0) & 0xFF; //把要被写入的地址拆分
//Read data from T613
//第一次写入从设备地址和regAddr的前2bytes,最后跟一个byte dummy数据。
IIC_WriteSingleByte(SLAVE_ADDR_READ1, REG_ADDR1, REG_ADDR2, &DUMMY);
//第二次写入从设备地址和regAddr的后2bytes,然后读出数据内容。
IIC_ReadSingleRegValue(SLAVE_ADDR_READ2, REG_ADDR3, REG_ADDR4, &test_Rdata);
// . . .伪代码 ,Read data from T613. . .