最近这几天自己写了一个spi的驱动,但是写的过程中遇到了不少的小问题,给我卡了最长时间的就是这个状态机跳转的问题。在经过七八个小时的不断修改下,终于可以了。

可能是之前写这些时序都基本是照着别人的写的,所以有很多细节处没有注意到,今天完全独立设计一个稍微复杂一点点的时序才意识到这些细节的重要,这也是在自己的思考的解决办法和再次看了几次之前仿照着别人一些教程写的代码的一些总结。希望能在大家的学习过程中帮到大家,跳过这个坑。

在写状态机的时候,状态之间的跳转常用一些标志来完成,而每个状态下,判断是否达到状态反转的条件会对一些计数器进行判断。

如果标志跳变和计数器的清零在同一个状态下发生,这个时候就会出现一种情况:

因为状态标志位跳变后,下一个周期系统才会跳转到另一个状态,所以在下个周期刚到的时候,系统依然是当前的周期,所以,而这个时候,计数器的值已经清零0,则系统会再次执行当前周期下的语句,而里面对计数器的值进行判断时,计数器的值是按照0来看的,所以可能会执行对计数器加一之类的操作

而如果这个计时器,并不只有这一个状态下会被使用,则会对其他状态产生影响,甚至报错。

【例】

一般vlan 一般vlog存在的问题有哪些_fpga


一般vlan 一般vlog存在的问题有哪些_赋值_02


一般vlan 一般vlog存在的问题有哪些_一般vlan_03

在这个代码中,就是由于在S_WAIT状态下,delay_done和time_count同时清零,而在下一个周期刚来的时候,系统还会处于S_WAIT状态一个周期,而这个时候time_count的值被清空了,所以,time_count在此时S_WAIT的判断下,会自加一次,故系统正真跳转到S_SEND的时候,time_count的值已经不是0,而是1了,导致后面的逻辑全部错误。

解决方法:

1、 在原来状态对计数器累加的时候加一个限制条件,如果状态标志为高则不进入

一般vlan 一般vlog存在的问题有哪些_verilog_04

2、把状态完成标志先于状态真正完成一个周期拉高,而计数器还是等到状态正真结束时清零(即状态完成标志要早于计数器清零一个周期)(这样处理显然是更好的,因为根据前面的分析,在我们以为的状态结束后还会持续一个周期,这样处理则系统跳转的时刻才是我们正真想要的时刻,并且也不会再出现刚刚那样的问题)

**3、 把每个状态的执行内容的判断条件改成next_stage,这样上述问题都不需要考虑,可以正真的实现系统的状态和自己想要的一样,不存在每个状态都会往后延时一个周期的问题。(因为next_stage是和标志位同步变化的,所以标志位变化下一个周期系统就会执行相应的跳转,不会像now_stage一样存在存在一个周期的延时,可能会出很多问题)

注: 用next_stage做条件的相当于条件改变则状态立即改变,故用next_stage得时候要注意的是用同一个标志位做条件跳转标志,并且还想用此标志位给当前状态赋值,则会出问题,因为下一个时钟来的时候已经跳转了,所以这个赋值自然不会执行。
所以只要没有上述需求,基本上优先使用next_stage做判断条件**