贾工 先楫资深 FAE
12年产品研发经验,具有变频器、伺服等工业产品开发经验,也负责过激光投影显示系统开发、AI应用开发、PYQT、Linux驱动开发等工作。
1、SEI简介
SEI(Serial Encoder Interface)串行编码器接口,是先楫半导体创新性设计的一个针对串行绝对值编码器通信的外设。SEI支持同步通信模式与异步通信模式,既能做主机——从编码器获取数据,又能做从机——将位置信息以主机需要的串行协议发出。在电机类应用中极大的降低了编码器相关开发任务的难度,同时以硬件编解码的方式降低了CPU负载率,让CPU有更多算力处理其他任务。
先楫半导体SDK 1.5.0提供了诸多SEI应用的实例,包括BISS-C、Endat、Hiperface、Nikon、SSI、Tamagawa等串行协议的主站、从站配置源码,开发者在sample实例的基础上,简单的进行修改即可应用到项目中。
本文以Tamagawa协议为例,对SEI在异步通信中用法进行讲解,同时对slave例程进行修改,增加对Tamagawa协议中EEPROM指令的支持,使读者对SEI的用法有进一步的认识与了解。
本文中,命令指协议中主站向从站发送的命令,从站需要根据命令内容进行回复或执行某些操作;指令指SEI引擎执行的动作。
1.1SEI关键概念
1.1.1数据寄存器
数据寄存器是SEI收发数据的数据存放单元。在通信的接收过程中,接收到的数据会被存放于数据寄存器中;在通信的发送过程中,需要向外发送的数据同样存放在数据寄存器中。
SEI共有9组数据寄存器,每个寄存器宽度为32bit。当以字节(8bit)为单位进行收发时,可以只使用数据寄存器的bit0~bit7,也可以使用bit0~bit32(或bit0~bit23),此时SEI引擎会自动将数据每8bit为一个单位,增加起始位、奇偶校验位、结束位等进行收发。例如有一个24bit的编码器单圈位置数据,接收时虽然每8bit接收1包,但连续收到的3包数据会放到同一个数据寄存器内;发送时,用户在数据寄存器的bit0~bit23填入数据,SEI引擎会自动拆包,将bit0~bit7、bit8~bit15、bit16~bit23分别增加起始位、奇偶校验位、结束位对外发出。
数据寄存器0用于忽略接收到的数据——某些开发者不关心的数据可以使用数据数据寄存器0进行接收;其概念与linux系统下黑洞文件类似。
数据寄存器2~数据寄存器9为通用数据寄存器。可以工作在3种模式下:
1)数据模式:仅用于存储数据;
2)检查模式:可设定期待值,例如用户期待接收到0x17,当接收到的写入该数据寄存器的值不为0x17时,可产生传输错误提示;
3)CRC模式:用于收发数据过程中实时计算CRC值,可通过设置CRC多项式与CRC初始值来设计CRC算法,当接收数据的CRC计算结果与实时计算结果不符时,可产生错误传输提示。
1.1.2命令寄存器
用于接收串行编码器协议中的命令数据。例如Tamagawa协议中CF(Control Field)字段为命令,其含义如下图:
可以看到,CF字段内的cc0~cc3决定了通信的内容,根据该字段的不同,主机可以从编码器中读取单圈位置数据、多圈位置数据、报警信息、操作EEPROM等。
1.1.3命令匹配表
命令寄存器接收到命令后,SEI引擎接收JUMP跳转指令,会根据命令内容在命令匹配表内进行检索。找到符合命令的表项后,则跳转至该命令匹配表指向的指令开始执行。SEI共支持8张命令匹配表,SEI引擎会以顺序方式对每张命令匹配表的命令进行对比,如果命令匹配表0~命令匹配表6都匹配失败,则无条件执行命令匹配表7的预设指令(回复/不回复)。
1.1.4指令
SEI引擎共支持8种指令,分为停止、等待、接收、发送、跳转5大类指令,根据是否有超时保护拓展为8种指令。例如接收指令可分为时限内接收与无限时接收,时限内接收在规定的时间内未收到数据会进行报错处理,无限时接收则会永远等待下去。其它时限内发送与无限时发送等概念,请读者自行理解。SEI共支持预设64条指令。
1.1.5状态机
SEI状态机包括4个状态,状态的切换只能以0-->1-->2-->3-->0的顺序进行,每种状态的切换条件可由开发者自行定义,例如设置执行完第10条指令后状态机从状态0切换到状态1。状态切换可向外发送事件信号,开发者可将该信号拉到其它外设进行触发,实现硬件同步;或简单的产生一次中断或DMA事件,使用中断或DMA进行一定的数据处理工作。
理解SEI工作的关键就在于以上5个概念的掌握。其它更多的技术细节需要读者自行查阅UM手册进行理解。下面就以这5个概念对SEI工作的流程进行直观的举例描述:
1)从机开始以指令0“接收”状态等待主机发送CF字段,若接收到数据,将接收到的指令保存到指令寄存器;
2)例如收到了DATA ID3指令,接收到指令后检查指令匹配表;
3)顺序检查8张指令匹配表进行指令匹配,例如匹配到了指令表1,该指令表内描述“收到DATA ID3后执行预设的64条指令中的指令10”;
4)SEI引擎执行指令10,指令10内容为“时限内发送,CF,CF存放于指令寄存器”;
5)SEI引擎执行指令11,指令11内容为“时限内发送,SF,SF存放于数据寄存器2”;
6)SEI引擎执行指令12,指令12内容为“时限内发送,ABS0~ABS2,ABS存放于数据寄存器3”;
7)SEI引擎执行指令13,指令13内容为“时限内发送,ENID,ENID存放于数据寄存器4”;
8)SEI引擎执行指令14,指令14内容为“时限内发送,ABM,ABM存放于数据寄存器5”;
9)SEI引擎执行指令15,指令15内容为“时限内发送,ALC,ALC存放于数据寄存器6”;
10)SEI引擎执行指令16,指令16内容为“时限内发送,CRC,CRC存放于数据寄存器9”;
11)SEI引擎执行指令17,指令17内容为“结束,跳转回指令0”;
12)SEI引擎执行指令0,指令0内容为“接收,等待主机发送CF字段,若接收到数据,将接收到的指令保存到指令寄存器”。
可以看到,通过以上工作流程的描述,SEI就依靠硬件自动完成了数据的发送,响应了主机读数据的需求。CPU只要在合适的时间点将数据更新到数据寄存器即可。
2 多摩川协议简介
多摩川编码器在工业控制领域广泛应用,本节简单介绍Tamagawa编码器协议。
注意,协议整体架构是固定的,但具体到每款编码器,根据编码器精度不同、多圈数据位数不同,协议的数据内容需要进行微调。
多摩川编码器支持向主站提供单圈位置信息、多圈位置信息、报警信息、复位操作、EEPROM读写操作等,不同操作指令的下发位于CF字段内。下面分别介绍协议内不同指令的具体格式。
具体的,多摩川协议以2.5M固定波特率进行数通信,数据格式8、N、1。
2.1数据读取指令格式
数据读取过程:
1)主机下发CF,CF内的cc0~cc3为ID0~ID3时,代表读取编码器信息;
2)从机回复CF,响应主机;
3)从机回复SF,发送编码器状态信息(具体有什么状态Flag请读者自行学习多摩川编码器Datasheet);
4)从机回复DF0~DF7,即数据字段。根据不同的指令ID,数据字段长度不同,数据字段内可包含ABS(单圈信息),ENID(固定0x17),ABM(多圈信息),ALMC(报警信息),不同ID回复内容见下表。
5)从机回复CRC,供主机进行数据完整性校验。
时序要求如下,在收到CF后的0.5us时刻锁存当前位置信息:
2.2EEPROM读指令格式
多摩川编码器为客户提供了762字节的EEPROM空间,分为6页,每页包含127个(0~126)字节。对地址127进行写操作可改变操作页数。
1)主机发送CF,CF内cc0~cc3字段解析为ID D;
2)主机发送ADF,代表要读取当前页的第ADF个(0~126)字节的数据;
3)主机发送CRC,供从机进行数据完整性校验;
4)从机回复CF、ADF;
5)从机回复EDF,即主机需要的数据;
6)从机回复CRC,供主机进行数据完整性校验。
2.3EEPROM写指令格式
1)主机发送CF,CF内cc0~cc3字段解析为ID 6;
2)主机发送ADF,代表要写入当前页的第ADF个(0~126)字节;
3)主机发送EDF,代表要写入的数据;
4)主机发送CRC,供从机进行数据完整性校验;
5)从机回复CF、ADF、EDF、CRC,与主机下发内容相同,代表写入成功。
读写时序要求如下:
3多摩川从站例程介绍
打开
sdk_env_v1.5.0\hpm_sdk\samples\drivers\sei\slave\tamagawa\src文件,获取Tamagawa从站源码。
/* [1] tranceiver config */
tranceiver_config.mode
=sei_asynchronous_mode;
tranceiver_config.tri_sample
=
false
;
tranceiver_config.src_clk_freq
=clock_get_frequency(
BOARD_MOTOR_CLK_NAME
)
;
tranceiver_config.asynchronous_config.wait_len
=
0
;
tranceiver_config.asynchronous_config.data_len
=
8
;
tranceiver_config.asynchronous_config.parity_enable
=
false
;
tranceiver_config.asynchronous_config.data_idle_high_z
=
false
;
tranceiver_config.asynchronous_config.data_idle_state
= sei_idle_high_state;
tranceiver_config.asynchronous_config.baudrate
=
2500000;
sei_tranceiver_config_init
(
BOARD_SEI
BOARD_SEI_CTRL
&
tranceiver_config
);
设置SEI工作在异步模式,波特率为2.5M,数据格式为8、N、1。以及数据线的默认状态等,这一部分请读者自行对照UM手册SEI寄存器进行解析。
/* [2] data register config */
/* cmd register : recv CF */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order
= sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len
= 8;
data_format_config.last_bit
= 7;
data_format_config.first_bit
= 0;
data_format_config.max_bit
= 7;
data_format_config.min_bit
= 0;
sei_cmd_data_format_config_init
(BOARD_SEI,SEI_SELECT_CMD,BOARD_SEI_CTRL
&data_format_config);
/* data register 4: send SF */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag
=
false;
data_format_config.bit_order
= sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len
= 8;
data_format_config.last_bit
= 7;
data_format_config.first_bit
= 0;
data_format_config.max_bit
= 7;
data_format_config.min_bit
= 0;
sei_cmd_data_format_config_init
(
BOARD_SEI, SEI_SELECT_DATA, SEI_DAT_4
&data_format_config);
/* data register 5: send ABS0 ABS1 ABS2 */
data_format_config.mode=
sei_data_mode
;
data_format_config.signed_flag=
false
;
data_format_config.bit_order=
sei_bit_lsb_first;
data_format_config.word_order=
sei_word_nonreverse;
data_format_config.word_len=
24
;
data_format_config.last_bit=
23
;
data_format_config.first_bit=
0;
data_format_config.max_bit=
23;
data_format_config.min_bit=
0;
sei_cmd_data_format_config_init
(
BOARD_SEI, SEI_SELECT_DATA, SEI_DAT_5
&
data_format_config
);
/* data register 6: send ENID */
data_format_config.mode=
sei_data_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order=
sei_bit_lsb_first;
data_format_config.word_order=
sei_word_nonreverse;
data_format_config.word_len=
8;
data_format_config.last_bit=
7;
data_format_config.first_bit=
0;
data_format_config.max_bit=
7;
data_format_config.min_bit=
0;
sei_cmd_data_format_config_init
(BOARD_SEI, SEI_SELECT_DATA, SEI_DAT_6
&
data_format_config);
/* data register 7: send ABM0 ABM1 ABM2 */
data_format_config.mode=
sei_data_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order=
sei_bit_lsb_first;
data_format_config.word_order=
sei_word_nonreverse;
data_format_config.word_len=
24
;
data_format_config.last_bit=
23
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
23
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI, SEI_SELECT_DATA, SEI_DAT_7
&data_format_config);
/* data register 8: send ALMC */
data_format_config.mode=
sei_data_mode
;
data_format_config.signed_flag=
false
;
data_format_config.bit_order=
sei_bit_lsb_first;
data_format_config.word_order=
sei_word_nonreverse;
data_format_config.word_len=
8
;
data_format_config.last_bit=
7
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
7
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI, SEI_SELECT_DATA, SEI_DAT_8
&
data_format_config);
/* data register 9: send crc */
data_format_config.mode=
sei_crc_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order
=sei_bit_lsb_first;
data_format_config.word_order
=sei_word_nonreverse;
data_format_config.word_len=
8
;
data_format_config.crc_invert=
false
;
data_format_config.crc_shift_mode=
false
;
data_format_config.crc_len=
8
;
data_format_config.last_bit=
7
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
7
;
data_format_config.min_bit=
0
;
data_format_config.crc_init_value=
0
;
data_format_config.crc_poly=
1
;
sei_cmd_data_format_config_init
(
BOARD_SEI, SEI_SELECT_DATA, SEI_DAT_9
&
data_format_config);
设置数据寄存器,其中:
1)指令寄存器用于收发CF;
2)DATA4(数据寄存器4)用于发送SF;
3)DATA5(数据寄存器5)用于发送ABS;
4)DATA6(数据寄存器6)用于发送ENID;
5)DATA7(数据寄存器7)用于发送ABM;
6)DATA8(数据寄存器8)用于发送ALM;
7)DATA9(数据寄存器9)用于发送CRC;
/* [3] instructions */
instr_idx
= 0;
/* instr0 : Recv CF */
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_RECV_WDG
0
SEI_DAT_0, SEI_DAT_1,
8
);
/* instr1 : halt 1 bit for update */
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_HALT
0
SEI_DAT_0
SEI_DAT_0
1
);
/* instr2 : halt some bits for waiting */
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_HALT
0,
SEI_DAT_0
SEI_DAT_0
6
);
/* instr3 : jump to cmd table instr_idx[0] */
sei_set_instr(BOARD_SEI
instr_idx
++
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0,
SEI_JUMP_CMD_TABLE_INSTR_IDX0);
/* Data ID0 : 0x02 */
/*instr4 : sendCF */
sei_set_instr(BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND
0
SEI_DAT_9, SEI_DAT_1,
8
);
/* instr5 : send SF */
sei_set_instr
(
BOARD_SEI
instr_idx
++
SEI_INSTR_OP_SEND
0
SEI_DAT_9, SEI_DAT_4,
8
);
/*instr6 :send ST(POS) */
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND
0
SEI_DAT_9, SEI_DAT_5,
24
);
/*instr7 :CRC */
sei_set_instr(
BOARD_SEI
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_0, SEI_DAT_9,
8
);
/*instr8 :Jump back to initiate*/
sei_set_instr
(
BOARD_SEI
instr_idx
++
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_INIT_INSTR_IDX
);
/* Data ID1 : 0x8A */
/* Reference to instr0 ~ instr8 */
sei_set_instr
(
BOARD_SEI
instr_idx
++
SEI_INSTR_OP_SEND, 0, SEI_DAT_9, SEI_DAT_1, 8);
/* CF */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_4,
8
);
/* SF */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_7,
24
);
/* MT */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_0, SEI_DAT_9,
8
);
/* CRC */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_INIT_INSTR_IDX);
/* Data ID2 : 0x92 */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_1,
8
);
/* CF */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_4,
8
);
/* SF */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_6,
8
);
/* ENID:0x17 */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_0, SEI_DAT_9,
8
);
/* CRC */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_INIT_INSTR_IDX);
/* Data ID3 : 0x1A */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_1,
8
);
/* CF */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_4,
8
);
/* SF */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_5,
24
);
/* ST(POS) */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_6,
8
);
/* ENID:0x17 */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_7,
24
);
/* MT */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_8,
8
);
/* ALMC */
sei_set_instr
(BOARD_SEI,
instr_idx
++
SEI_INSTR_OP_SEND, 0, SEI_DAT_0, SEI_DAT_9,
8
);
/* CRC */
sei_set_instr
(BOARD_SEI,
instr_idx
++,
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_INIT_INSTR_IDX);
设置预设指令,其中:
1)指令0用于接收CF;
2)指令1用于延迟0.5us后锁存位置信息;
3)指令2用于延迟3us满足时序要求;
4)指令3用于跳转,查找指令匹配表进行匹配;
5)指令4~指令表结束,根据不同的指令向主机发送主机查询的信息。
/* [4] command table */
command_table_config.cmd_min_value=
0x02u;
command_table_config.cmd_max_value=
0x02u;
command_table_config.cmd_mask_value=
0xFFu;
command_table_config.instr_idx[
0
] =
4;
sei_cmd_table_config_init
(
BOARD_SEI, BOARD_SEI_CTRL, SEI_CMD_TABLE_0,
&
command_table_config
);
command_table_config.cmd_min_value
= 0x8Au;
command_table_config.cmd_max_value
= 0x8Au;
command_table_config.cmd_mask_value
= 0xFFu;
command_table_config.instr_idx[0]
= 9;
sei_cmd_table_config_init
(
BOARD_SEI, BOARD_SEI_CTRL, SEI_CMD_TABLE_1,
&
command_table_config
);
command_table_config.cmd_min_value
= 0x92u;
command_table_config.cmd_max_value
= 0x92u;
command_table_config.cmd_mask_value
= 0xFFu;
command_table_config.instr_idx[0]
= 14;
sei_cmd_table_config_init
(
BOARD_SEI, BOARD_SEI_CTRL, SEI_CMD_TABLE_2,
&
command_table_config);
command_table_config.cmd_min_value
= 0x1Au;
command_table_config.cmd_max_value
= 0x1Au;
command_table_config.cmd_mask_value
= 0xFFu;
command_table_config.instr_idx[0]
= 19;
sei_cmd_table_config_init
(BOARD_SEI, BOARD_SEI_CTRL, SEI_CMD_TABLE_3,
&
command_table_config);
设置指令匹配表,
cmd_min_value、cmd_max_value、cmd_mask_value设置了指令匹配的模式,请参考UM手册查询具体的含义;instr_idx[0]设置了如果匹配成功,跳转的目标指令。
/* [5] state transition config */
/* latch0 */
state_transition_config.disable_clk_check=
true;
state_transition_config.disable_txd_check=
true;
state_transition_config.disable_rxd_check=
true;
state_transition_config.disable_timeout_check=
true;
state_transition_config.disable_instr_ptr_check=
false;
state_transition_config.instr_ptr_cfg
= sei_state_tran_condition_fall_leave;
state_transition_config.instr_ptr_value
= 1;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL, SEI_LATCH_0, SEI_CTRL_LATCH_TRAN_0_1,
&
state_transition_config);
state_transition_config.disable_clk_check
= true;
state_transition_config.disable_txd_check
= true;
state_transition_config.disable_rxd_check
= true;
state_transition_config.disable_timeout_check
= true;
state_transition_config.disable_instr_ptr_check
= true;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL, SEI_LATCH_0, SEI_CTRL_LATCH_TRAN_1_2,
&
state_transition_config);
state_transition_config.disable_clk_check
= true;
state_transition_config.disable_txd_check
= true;
state_transition_config.disable_rxd_check
= true;
state_transition_config.disable_timeout_check
= true;
state_transition_config.disable_instr_ptr_chec
k
= true;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL, SEI_LATCH_0, SEI_CTRL_LATCH_TRAN_2_3,
&
state_transition_config);
state_transition_config.disable_clk_check
= true;
state_transition_config.disable_txd_check
= true;
state_transition_config.disable_rxd_check
= true;
state_transition_config.disable_timeout_check
= true;
state_transition_config.disable_instr_ptr_check
= true;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL, SEI_LATCH_0, SEI_CTRL_LATCH_TRAN_3_0,
&
state_transition_config);
state_transition_latch_config.enable
= true;
state_transition_latch_config.output_select=
SEI_CTRL_LATCH_TRAN_0_1;
state_transition_latch_config.delay=
0
;
sei_state_transition_latch_config_init
(
BOARD_SEI, BOARD_SEI_CTRL, SEI_LATCH_0,
&
state_transition_latch_config);
状态机跳转的配置代码,此处只配置了状态0到状态1转换的条件为“指令1执行完成”,即接收到CF后0.5us的时间点,进行状态转换,同时向外生成事件(本例程内产生了中断,中断内对要发送的数据进行了设置)。
/* [6] sample config*/
sample_config.pos_data_idx
= SEI_DAT_5;
sample_config.rev_data_idx
= SEI_DAT_7;
sample_config.pos_data_use_rx
= false;
sample_config.rev_data_use_rx
= false;
sample_config.sample_window
= 0x5;
sample_config.sample_once
= true;
sample_config.latch_selec
t= SEI_LATCH_0;
sample_config.data_register_select=
BIT5_MASK
|
BIT7_MASK;
/* SEI_DAT_5, SEI_DAT_7 */
sei_sample_config_init
(BOARD_SEI, BOARD_SEI_CTRL,
&
sample_config
);
sei_set_sample_pos_override_value(
BOARD_SEI, BOARD_SEI_CTRL
mock_pos
);
sei_set_sample_rev_override_value(
BOARD_SEI, BOARD_SEI_CTRL,
mock_rev
);
/* [7] interrupt config */
intc_m_enable_irq_with_priority(BOARD_SEI_IRQn,
1
);
sei_set_irq_enable(
BOARD_SEI, BOARD_SEI_CTRL
sei_irq_latch0_event | sei_irq_wdog_event | sei_irq_trx_err_event,
true
);
采样设置(读取电机系统内的位置信息)与中断开启,状态0到状态1实现状态转换时,出发了sei_irq_latch0_event中断。
/* [8] enbale sync timer timestamp */
synt_enable_timestamp
(
HPM_SYNT, true
);
/* [9] engine config */
printf
(
"Started sei engine!\n"
);
engine_config.arming_mode
= sei_arming_direct_exec;
engine_config.data_cdm_idx
= 0;
engine_config.data_base_idx
= 0;
engine_config.init_instr_idx
= 0;
engine_config.wdg_enable
= true;
engine_config.wdg_action=
sei_wdg_exec_exception_instr;
engine_config.wdg_instr_idx
= 0;
engine_config.wdg_time
= 1000;
/* 1000 bits time */
sei_engine_config_init
(
BOARD_SEI, BOARD_SEI_CTRL,
&
engine_config);
sei_set_engine_enable
(BOARD_SEI, BOARD_SEI_CTRL, true);
看门狗的设置及使能SEI引擎,看门狗的配置含义请参考UM手册。
voi
disr_sei
(void)
{
uint32_t
delta
;
if
(
sei_get_irq_status
(BOARD_SEI, BOARD_SEI_CTRL,
sei_irq_latch0_event
))
{
sei_clear_irq_flag
(BOARD_SEI, BOARD_SEI_CTRL,
sei_irq_latch0_event
);
sample_latch_tm1
=
sei_get_latch_time
(BOARD_SEI, BOARD_SEI_CTRL, SEI_LATCH_0);
mock_pos
++;
if
(
mock_pos
> 0x00FFFFFF
)
{
mock_pos
= 0;
mock_rev
++;
if(mock_rev
> 0x00FFFFFF
)
{
mock_rev
= 0;
}
}
sei_set_sample_pos_override_value
(BOARD_SEI, BOARD_SEI_CTRL,
mock_pos
);
sei_set_sample_rev_override_value(
BOARD_SEI, BOARD_SEI_CTRL
mock_rev
);
sei_set_data_value(
BOARD_SEI, SEI_DAT_4
0x00
);
sei_set_data_value(
BOARD_SEI, SEI_DAT_6
0x17
);
sei_set_data_value(
BOARD_SEI, SEI_DAT_8
0x00
);
delta
=
(sample_latch_tm1> sample_latch_tm2
) ? (
sample_latch_tm1- sample_latch_tm2
) : (
sample_latch_tm1- sample_latch_tm2
+ 0xFFFFFFFFu
);
printf(
"CMD
:
%#x
SF:
%#x
ST:
%#x
ENID:
%#x
MT:
%#x,
ALMC
:
%#x
CRC
:
%#x
sample_tm1:
%u
sample_tm2
:
%u
sample_interval:
%d
us\n
",
sei_get_command_value(
BOARD_SEI, BOARD_SEI_CTRL
),
sei_get_data_value(
BOARD_SEI, SEI_DAT_4
),
sei_get_data_value(
BOARD_SEI, SEI_DAT_5
),
sei_get_data_value(
BOARD_SEI, SEI_DAT_6
),
sei_get_data_value(
BOARD_SEI, SEI_DAT_7
),
sei_get_data_value(
BOARD_SEI, SEI_DAT_8
),
sei_get_data_value(
BOARD_SEI, SEI_DAT_
9),
sample_latch_tm1, sample_latch_tm2, delta/
(clock_get_frequency(
BOARD_MOTOR_CLK_NAME
) /
1000000
));
sample_latch_tm2= sample_latch_tm1;
}
if
(sei_get_irq_status(
BOARD_SEI, BOARD_SEI_CTRL
sei_irq_wdog_event
)) {
sei_clear_irq_flag(
BOARD_SEI, BOARD_SEI_CTRL
sei_irq_wdog_event
);
sei_set_command_rewind(
BOARD_SEI, BOARD_SEI_CTRL
);
}
if
(sei_get_irq_status(
BOARD_SEI, BOARD_SEI_CTRL
sei_irq_trx_err_event
)) {
sei_clear_irq_flag(
BOARD_SEI, BOARD_SEI_CTRL
sei_irq_trx_err_event
);
printf(
"TRX Error!\n"
);
}
}
SEI中断设置,当sei_irq_latch0_event中断发生时,设置了向主机回复的数据,满足多摩川时序要求,即接收到CF后0.5us时间点进行数据设置。
4 EEPROM指令支持
由于读写EEPROM的指令格式与读取位置数据指令格式有区别,即接收CF后不进行锁存,需要继续接收ADF、EDF等数据,因此整个SEI指令处理流程上,指令的跳转逻辑变得更复杂。下图是在做EEPROM指令支持开发过程中,绘制的流程图。
支持EEPROM指令的关键源码如下:
uint32_t
eeprom_page
= 0;
uint32_t
eeprom[6][127]
= {0};
声明eeprom地址页信息变量与6页共762字节的eeprom数据数组。
/* [2] data register config */
/* cmd register : recv CF */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag=
false;
data_format_config.bit_order
= sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len=
8
;
data_format_config.last_bit=
7
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
7
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI,
SEI_SELECT_CMD
BOARD_SEI_CTRL, &
data_format_config);
/* cmd register : recv ADF */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag=
false;
data_format_config.bit_order
= sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len=
8
;
data_format_config.last_bit=
7
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
7
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI,
SEI_SELECT_DATA, SEI_DAT_2,
&
data_format_config);
/* cmd register : recv EDF */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order=
sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len=
8
;
data_format_config.last_bit=
7
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
7
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI,
SEI_SELECT_DATA, SEI_DAT_3,
&
data_format_config);
/* data register 4: send SF */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order
= sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len=
8
;
data_format_config.last_bit=
7
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
7
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI,
SEI_SELECT_DATA, SEI_DAT_4,
&
data_format_config);
/* data register 5: send ABS0 ABS1 ABS2 */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag
=
false
;
data_format_config.bit_order
=sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len=
24
;
data_format_config.last_bit=
23
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
23
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI,
SEI_SELECT_DATA, SEI_DAT_5,
&
data_format_config);
/* data register 6: send ENID */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order
= sei_bit_lsb_first;
data_format_config.word_orde
r= sei_word_nonreverse;
data_format_config.word_len=
8
;
data_format_config.last_bit=
7
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
7
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI,
SEI_SELECT_DATA, SEI_DAT_6,
&
data_format_config);
/* data register 7: send ABM0 ABM1 ABM2 */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order
= sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len=
24
;
data_format_config.last_bit=
23
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
23
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI,
SEI_SELECT_DATA, SEI_DAT_7,
&
data_format_config);
/* data register 8: send ALMC */
data_format_config.mode
= sei_data_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order
= sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len=
8
;
data_format_config.last_bit=
7
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
7
;
data_format_config.min_bit=
0
;
sei_cmd_data_format_config_init
(
BOARD_SEI,
SEI_SELECT_DATA, SEI_DAT_8,
&
data_format_config);
/* data register 9: send crc */
data_format_config.mode
= sei_crc_mode;
data_format_config.signed_flag=
false
;
data_format_config.bit_order
= sei_bit_lsb_first;
data_format_config.word_order
= sei_word_nonreverse;
data_format_config.word_len=
8
;
data_format_config.crc_invert=
false
;
data_format_config.crc_shift_mode=
false
;
data_format_config.crc_len=
8
;
data_format_config.last_bit=
7
;
data_format_config.first_bit=
0
;
data_format_config.max_bit=
7
;
data_format_config.min_bit=
0
;
data_format_config.crc_init_value=
0
;
data_format_config.crc_poly=
1
;
sei_cmd_data_format_config_init
(
BOARD_SEI,
SEI_SELECT_DATA, SEI_DAT_9,
&
data_format_config);
设置数据寄存器,其中:
1)指令寄存器用于收发CF
2)DATA2(数据寄存器2)用于收发ADF
3)DATA3(数据寄存器3)用于发送EDF
4)DATA4(数据寄存器4)用于发送SF
5)DATA5(数据寄存器5)用于发送ABS
6)DATA6(数据寄存器6)用于发送ENID
7)DATA7(数据寄存器7)用于发送ABM
8)DATA8(数据寄存器8)用于发送ALM
9)DATA9(数据寄存器9)用于发送CRC
/* [3] instructions */
instr_idx
= 0;
/*00*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_RECV_WDG,
0
SEI_DAT_9, SEI_DAT_1,
8
);
/* Recv CF */
/* jump to cmd */
/*01*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_CMD_TABLE_INSTR_IDX0);
/* jump to cmd table instr_idx[0] */
/*02*/
sei_set_instr
(BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_HALT,
0
SEI_DAT_0, SEI_DAT_0,
1
);
/* halt 1 bit for update */
/*03*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_HALT,
0
SEI_DAT_0, SEI_DAT_0,
6
);
/* halt some bits for waiting */
/*04*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_CMD_TABLE_INSTR_IDX6);
/* Data ID0 : 0x02 */
/*05*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_1,
8
);
/* CF */
/*06*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_4,
8
);
/* SF */
/*07*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_5,
24
);
/* ST(POS) */
/*08*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_0, SEI_DAT_9,
8
);
/* CRC */
/*09*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_INIT_INSTR_IDX);
/* Data ID1 : 0x8A */
/*10*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_1,
8
);
/* CF */
/*11*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_4,
8
);
/* SF */
/*12*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_7, 24);
/* MT */
/*13*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_0, SEI_DAT_9, 8);
/* CRC */
/*14*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_INIT_INSTR_IDX);
/* Data ID2 : 0x92 */
/*15*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_1,
8
);
/* CF */
/*16*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_4,
8
);
/* SF */
/*17*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_6,
8
);
/* ENID:0x17 */
/*18*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_0, SEI_DAT_9,
8
);
/* CRC */
/*19*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_INIT_INSTR_IDX);
/* Data ID3 : 0x1A */
/*20*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_1,
8
);
/* CF */
/*21*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_4,
8
);
/* SF */
/*22*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_5,
24
);
/* ST(POS) */
/*23*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_6,
8
);
/* ENID:0x17 */
/*24*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_7,
24
);
/* MT */
/*25*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_8,
8
);
/* ALMC */
/*26*/
sei_set_instr
(
BOARD_SEI,
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_0, SEI_DAT_9,
8
);
/* CRC */
/*27*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_INIT_INSTR_IDX);
/* Data ID6 : 0x32 */ /*write to eeprom */
/*28*/
sei_set_instr
(
BOARD_SEI,
instr_idx
++,
SEI_INSTR_OP_RECV_WDG,
0
SEI_DAT_9, SEI_DAT_2,
8
);
/* ADF */
/*29*/
sei_set_instr
(
BOARD_SEI,
instr_idx
++,
SEI_INSTR_OP_RECV_WDG,
0
SEI_DAT_9, SEI_DAT_3,
8
);
/* EDF */
/*30*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_RECV_WDG,
0
SEI_DAT_0, SEI_DAT_9,
8
);
/* CRC */
/*31*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_CMD_TABLE_INSTR_IDX6);
/* Data IDD : 0xEA */ /*read from eeprom */
/*32*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_RECV_WDG,
0
SEI_DAT_9, SEI_DAT_2,
8
);
/* ADF */
/*33*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_RECV_WDG,
0
SEI_DAT_0, SEI_DAT_9,
8
);
/* CRC */
/*34*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_JUMP,
0
SEI_DAT_0, SEI_DAT_0, SEI_JUMP_CMD_TABLE_INSTR_IDX6);
/*response to write/read eeprom */
/*35*/
sei_set_instr
(
BOARD_SEI,
instr_idx
++,
SEI_INSTR_OP_HALT,
0
SEI_DAT_0, SEI_DAT_0,
1
);
/* halt 1 bit for update */
/*36*/
sei_set_inst
r(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_HALT,
0
SEI_DAT_0, SEI_DAT_0,
6
);
/* halt some bits for waiting */
/*37*/
sei_set_instr
(
BOARD_SEI
instr_idx
++
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_1,
8
);
/* CF */
/*38*/
sei_set_instr
(
BOARD_SEI,
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_2,
8
);
/* ADF */
/*39*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_9, SEI_DAT_3,
8
);
/* EDF */
/*40*/
sei_set_instr
(
BOARD_SEI
instr_idx
++,
SEI_INSTR_OP_SEND,
0
SEI_DAT_0, SEI_DAT_9,
8
);
/* CRC */
/*41*/
sei_set_instr
(
BOARD_SEI,
instr_idx
++,
SEI_INSTR_OP_JUMP, 0, SEI_DAT_0, SEI_DAT_0, SEI_JUMP_INIT_INSTR_IDX);
以上代码为根据流程图编写的新指令预设内容。
/* [4] command table */
command_table_config.cmd_min_value
= 0x02u;
command_table_config.cmd_max_value
= 0x02u;
command_table_config.cmd_mask_value
= 0xFFu;
command_table_config.instr_idx[0]
= 2;
command_table_config.instr_idx[6]
= 05;
sei_cmd_table_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_CMD_TABLE_0,
&
command_table_config);
command_table_config.cmd_min_value
= 0x8Au;
command_table_config.cmd_max_value
= 0x8Au;
command_table_config.cmd_mask_value
= 0xFFu;
command_table_config.instr_idx[0]
= 2;
command_table_config.instr_idx[6]
= 10;
sei_cmd_table_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_CMD_TABLE_1,
&
command_table_config);
command_table_config.cmd_min_value
= 0x92u;
command_table_config.cmd_max_value
= 0x92u;
command_table_config.cmd_mask_value
= 0xFFu;
command_table_config.instr_idx[0]
= 2;
command_table_config.instr_idx[6]
= 15;
sei_cmd_table_config_init
(BO
ARD_SEI, BOARD_SEI_CTRL
SEI_CMD_TABLE_2,
&
command_table_config);
command_table_config.cmd_min_value
= 0x1Au;
command_table_config.cmd_max_value
= 0x1Au;
command_table_config.cmd_mask_value
= 0xFFu;
command_table_config.instr_idx[0]
= 2;
command_table_config.instr_idx[6]
= 20;
sei_cmd_table_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_CMD_TABLE_3,
&
command_table_config);
command_table_config.cmd_min_value
= 0x32u;
command_table_config.cmd_max_value
= 0x32u;
command_table_config.cmd_mask_value
= 0xFFu;
command_table_config.instr_idx[0]
= 28;
command_table_config.instr_idx[6]
= 35;
sei_cmd_table_config_init
(
BOARD_SEI, BOARD_SEI_CTRL,
SEI_CMD_TABLE_4,
&
command_table_config);
command_table_config.cmd_min_value
= 0xEAu;
command_table_config.cmd_max_value
= 0xEAu;
command_table_config.cmd_mask_value
= 0xFFu;
command_table_config.instr_idx[0]
= 32;
command_table_config.instr_idx[6]
= 35;
sei_cmd_table_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_CMD_TABLE_5,
&
command_table_config);
以上代码为根据流程图编写的新指令匹配表。
/* [5] state transition config */
/* latch0 */
state_transition_config.disable_clk_check
= true;
state_transition_config.disable_txd_check
= true;
state_transition_config.disable_rxd_check
= true;
state_transition_config.disable_timeout_check
= true;
state_transition_config.disable_instr_ptr_check
= false;
state_transition_config.instr_ptr_cfg=
sei_state_tran_condition_fall_leave;
state_transition_config.instr_ptr_value
= 2;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_LATCH_0, SEI_CTRL_LATCH_TRAN_0_1,
&
state_transition_config);
state_transition_config.disable_clk_check
= true;
state_transition_config.disable_txd_check
= true;
state_transition_config.disable_rxd_check
= true;
state_transition_config.disable_timeout_check
= true;
state_transition_config.disable_instr_ptr_check
= true;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_LATCH_0, SEI_CTRL_LATCH_TRAN_1_2
&
state_transition_config);
state_transition_config.disable_clk_check
= true;
state_transition_config.disable_txd_check
= true;
state_transition_config.disable_rxd_check
= true;
state_transition_config.disable_timeout_check
= true;
state_transition_config.disable_instr_ptr_check
= true;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_LATCH_0, SEI_CTRL_LATCH_TRAN_2_3
&
state_transition_config);
state_transition_config.disable_clk_check
= true;
state_transition_config.disable_txd_check
= true;
state_transition_config.disable_rxd_check
= true;
state_transition_config.disable_timeout_check
= true;
state_transition_config.disable_instr_ptr_check
= true;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_LATCH_0, SEI_CTRL_LATCH_TRAN_3_0,
&
state_transition_config);
state_transition_latch_config.enable=
true;
state_transition_latch_config.output_select=
SEI_CTRL_LATCH_TRAN_0_1;
state_transition_latch_config.delay=
0
;
sei_state_transition_latch_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_LATCH_0,
&
state_transition_latch_config);
/* [6] state transition config */
/* latch1 */
state_transition_config.disable_clk_check
= true;
state_transition_config.disable_txd_check
= true;
state_transition_config.disable_rxd_check
= true;
state_transition_config.disable_timeout_check
= true;
state_transition_config.disable_instr_ptr_check
= false;
state_transition_config.instr_ptr_cfg=
sei_state_tran_condition_fall_leave;
state_transition_config.instr_ptr_value=
35;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_LATCH_1, SEI_CTRL_LATCH_TRAN_0_1,
&
state_transition_config);
state_transition_config.disable_clk_check=
true;
state_transition_config.disable_txd_check=
true;
state_transition_config.disable_rxd_check=
true;
state_transition_config.disable_timeout_check=
true;
state_transition_config.disable_instr_ptr_check=
true;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL,
SEI_LATCH_1, SEI_CTRL_LATCH_TRAN_1_2,
&
state_transition_config);
state_transition_config.disable_clk_check=
true;
state_transition_config.disable_txd_check=
true;
state_transition_config.disable_rxd_check=
true;
state_transition_config.disable_timeout_check=
true;
state_transition_config.disable_instr_ptr_check=
true;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_LATCH_1, SEI_CTRL_LATCH_TRAN_2_3,
&
state_transition_config);
state_transition_config.disable_clk_check=
true
;
state_transition_config.disable_txd_check=
true
;
state_transition_config.disable_rxd_check=
true
;
state_transition_config.disable_timeout_check=
true
;
state_transition_config.disable_instr_ptr_check=
true
;
sei_state_transition_config_init
(
BOARD_SEI, BOARD_SEI_CTRL
SEI_LATCH_1, SEI_CTRL_LATCH_TRAN_3_0
&
state_transition_config);
state_transition_latch_config.enable=
true;
state_transition_latch_config.output_select=
SEI_CTRL_LATCH_TRAN_0_1;
state_transition_latch_config.delay=
0;
sei_state_transition_latch_config_init
(
BOARD_SEI, BOARD_SEI_CTRL,
SEI_LATCH_1
&
state_transition_latch_config);
锁存器0配置为执行完指令2(读取位置信息CF的0.5us锁存点)后进行位置锁存;
锁存器1配置为执行完指令35(操作EEPROM指令CRC后0.5us锁存点)后进行EEPROM操作;
void
isr_sei(
void
)
{
uint32_t
delta;
if
(sei_get_irq_status(
BOARD_SEI, BOARD_SEI_CTRL, sei_irq_latch0_event)) {
sei_clear_irq_flag
(BOARD_SEI, BOARD_SEI_CTRL, sei_irq_latch0_event);
sei_set_data_rewind
(BOARD_SEI,
SEI_DAT_9
);
sample_latch_tm1
= sei_get_latch_time
(BOARD_SEI, BOARD_SEI_CTRL,
SEI_LATCH_0
);
mock_pos
++;
if
(
mock_pos
>
0x00FFFFFF
)
{
mock_pos
=
0
;
mock_rev
++;
if
(
mock_rev
>
0x00FFFFFF
)
{
mock_rev
=
0
;
}
}
sei_set_sample_pos_override_value
(BOARD_SEI, BOARD_SEI_CTRL,
mock_pos
);
sei_set_sample_rev_override_value
(BOARD_SEI, BOARD_SEI_CTRL,
mock_rev
);
sei_set_data_value(
BOARD_SEI
SEI_DAT_4
0x00
);
sei_set_data_value(
BOARD_SEI
SEI_DAT_6
0x17
);
sei_set_data_value(
BOARD_SEI,
SEI_DAT_8
0x00
);
delta= (sample_latch_tm1> sample_latch_tm2) ? (sample_latch_tm1- sample_latch_tm2) : (sample_latch_tm1- sample_latch_tm2+
0xFFFFFFFFu
);
printf(
"CMD:
%#x
SF:
%#x
ST:
%#x
ENID
:%#x,
MT:
%#x,
ALMC
:%#x,
CRC:
%#x,
sample_tm1:
%u,
sample_tm2:
%u
sample_interval:
%dus\n",
sei_get_command_value
(BOARD_SEI, BOARD_SEI_CTRL),
sei_get_data_value(
BOARD_SEI
SEI_DAT_4
),
sei_get_data_value(
BOARD_SEI
SEI_DAT_5
),
sei_get_data_value(
BOARD_SEI
SEI_DAT_6
),
sei_get_data_value(
BOARD_SEI
SEI_DAT_7
),
sei_get_data_value(
BOARD_SEI
SEI_DAT_8
),
sei_get_data_value(
BOARD_SEI
SEI_DAT_9
),
sample_latch_tm1, sample_latch_tm2, delta/
(clock_get_frequency
(BOARD_MOTOR_CLK_NAME) /
1000000
));
sample_latch_tm2= sample_latch_tm1
;
}
elseif
(sei_get_irq_status
(BOARD_SEI, BOARD_SEI_CTRL, sei_irq_latch1_event)) {
sei_clear_irq_flag
(BOARD_SEI, BOARD_SEI_CTRL, sei_irq_latch1_event);
uint32_t
cmd
= sei_get_command_value
(BOARD_SEI,
SEI_CTRL_1
);
if
(
cmd
==
0x32u
)
{
uint32_t
addr
= sei_get_data_value
(BOARD_SEI,
SEI_DAT_2
);
uint32_t
data
= sei_get_data_value
(BOARD_SEI,
SEI_DAT_3
);
if
(
addr
==
127
)
{
eeprom_page= data;
}
else
{
eeprom[eeprom_page][addr] = data;
}
}
elseif
(
cmd
==
0xEAu
)
{
uint32_t
addr
= sei_get_data_value
(BOARD_SEI,
SEI_DAT_2
);
sei_set_data_value(
BOARD_SEI
SEI_DAT_3, eeprom[eeprom_page][addr]);
}
}
if
(sei_get_irq_status(
BOARD_SEI, BOARD_SEI_CTRL
sei_irq_wdog_event)) {
sei_clear_irq_flag
(BOARD_SEI, BOARD_SEI_CTRL, sei_irq_wdog_event);
sei_set_command_rewind
(BOARD_SEI, BOARD_SEI_CTRL);
printf(
"WDG!
\n
"
);
}
if
(sei_get_irq_status
(BOARD_SEI, BOARD_SEI_CTRL, sei_irq_trx_err_event)) {
sei_clear_irq_flag
(BOARD_SEI, BOARD_SEI_CTRL, sei_irq_trx_err_event);
printf(
"TRX Error!
\n
"
);
}
}
在中断内,sei_irq_latch0_event分支处理位置锁存信息;sei_irq_latch1_event根据收到的指令信息对eeprom数组和地址页进行操作,更新数据/设置回复数据。
5 小结
相信通过以上针对SEI的讲解,及对多摩川协议、例程代码的分析与修改,读者对SEI有了更深的认识,希望开发者可以用好SEI模块,加速项目开发与落地。