[求助] 数据通过spi自stm32发送到cpld,cpld处理后发回出现问题,详细如下

amsams   2016-9-22 18:55 楼主
悬赏 10 分 芯积分未解决
我首先使用stm32通过spi发送数据到cpld,cpld处理数据后发回。问题的关键是,cpld中的程序的工作机制是这样的:我接受一切数据,甚至不区分什么帧头帧尾,什么位长。我cpld做的工作就是将收到的数据编码(收到的所有数据甚至空闲电平)都编码,经过低速光纤传输后在另一端把数据解码出来,包括什么空闲电平,帧头帧尾(当然,spi没用到帧头帧尾)。然后在通过spi传回给stm32。


可以看出,这种工作机制是很符合异步串行通信,但是spi是同步串行通信。所以stm32的spi预分频数只要超过了64,就无法接受到正确数据。通过示波器,我发现问题出在(看图)
搜狗截图20160922181734.png

从图上可以看出,在SCK(绿色波形,黄色波形是stm32的mosi发送数据)上升沿时,由于返回的数据和SCK不同步,导致SCK上升沿时不能每次都扫描到正确的电平。我认为解决的方法是:1、由于CPLD的时钟是50Mhz,而spi速度最高才是36/2=18M,只要将MISO(紫色波形)左移半个SCK,就可以保证SCK每次都扫描到正确的电平。
2、或者将收到的mosi的黄色波形数据收到后先不编码,左移半个SCK,然后再发送到编码。如图
搜狗截图20160922181803.png

但是,CPLD里的编码解码程序是别人写的,我不会改,我想单纯的在cpld的MoSi端,定义一个寄存器,然后在SCK的下降沿发送数据(stm32设置的是上升沿SCK检测电平)这样就能实现左移半个SCK。可是,写程序遇到了麻烦。
一个process中不能同时检测两个时钟沿。
可是我就是要在50Mhz的时钟下,检测spi的SCK的上升沿和下降沿啊。上升沿把数据存入寄存器。下降沿将数据发送到后面的编码器(别人的数据,我不会改,只能是保证它的不变,然后在前面加一个小模块,将小模块的输出当成它原来的输入给它)。


我写vhdl的思路是,第一个8bit数据,将数据存入a寄存器,第二个8bit数据传输周期,将数据存入b寄存器,同时在下降沿把a寄存器中数据发送到后面模块的输入,第三个8bit数据传输周期,将数据存入a寄存器,将b寄存器中数据发送到后面模块。这样不就同步了吗。

贴出来我写的那一些vhdl,帮忙告诉我怎么写,或者有解决上面问题的新思路。(我认为我上面的思路应该有逻辑错误,但我想了好久想不出来)谢谢了

signal TX:std_logic;
signal a:std_logic:='0';
signal b:std_logic:='0';
signal rx_shift_reg:std_logic_vector(7 downto 0):=(others=>'0');
signal rx_shift_reg_2:std_logic_vector(7 downto 0):=(others=>'0');
signal shift_cnt:std_logic_vector(3 downto 0):=(others=>'0');
signal shift_cnt_2:std_logic_vector(3 downto 0):=(others=>'0');
signal cnt:std_logic_vector(3 downto 0):=(others=>'0');
signal cnt_2:std_logic_vector(3 downto 0):=(others=>'0');


if rising_edge(spi_sck) then
        if(a='1')then
                rx_shift_reg<=rx_shift_reg(6 downto 0)& spi_din;
                shift_cnt<=shift_cnt+1;
                if(shift_cnt=x"07")then
                        b<='1';
                        a<=not a;
                end if;
        else
                rx_shift_reg_2<=rx_shift_reg_2(6 downto 0)& spi_din;
                shift_cnt_2<=shift_cnt_2+1;
                if(shift_cnt_2=x"07")then
                        b<='0';
                        a<=not a;
                end if;
        end if;
end if;
if(b='1')then
        if falling_edge(spi_sck) then
       
                cnt<=cnt+1;
                if(cnt=x"00")then
                        TX<=rx_shift_reg(7);
                else       
                        rx_shift_reg<=rx_shift_reg(6 downto 0)&'0';
                        TX<=rx_shift_reg(6);
                        if(cnt=x"07")then
                                cnt<=x"00";
                        end if;
                end if;
        end if;
else
        if falling_edge(spi_sck) then
                cnt_2<=cnt_2+1;
                if(cnt_2=x"00")then
                        TX<=rx_shift_reg_2(7);
                else       
                        rx_shift_reg_2<=rx_shift_reg_2(6 downto 0)&'0';
                        TX<=rx_shift_reg_2(6);
                        if(cnt_2=x"07")then
                                cnt_2<=x"00";
                        end if;
                end if;
        end if;
end if;



谢谢,头已炸
  • 搜狗截图20160922181734.png
  • 回复评论 (8)

    原来这个CPLD就是配合stm32的uart使用的,一切正常没问题。我就是要看看用速度更高的spi怎么弄,怎么处理。
    点赞  2016-9-22 19:00
    为啥我感觉你这个是上升沿捕获呀?你让他下降沿捕获就可以了吧。还有用PLL提高CPLD的频率。然后、、、、、、。
    点赞  2016-9-23 09:27
    引用: 1399866558 发表于 2016-9-23 09:27
    为啥我感觉你这个是上升沿捕获呀?你让他下降沿捕获就可以了吧。还有用PLL提高CPLD的频率。然后、、、、、 ...

    我这个是上升沿捕获,没错。但我想在cpld做这样的改动:mosi增加寄存器,使效果变成,下降沿捕获发送,miso还是上升沿发出
    点赞  2016-9-23 09:31
    引用: amsams 发表于 2016-9-23 09:31
    我这个是上升沿捕获,没错。但我想在cpld做这样的改动:mosi增加寄存器,使效果变成,下降沿捕获发送,mi ...

    CPLD端,你写的是上升沿触发,才会造成紫色的线滞后其他颜色的线半个周期。你把它改成下降沿触发,波形就会和黄色的线一样的波形。
    点赞  2016-9-23 09:49
    引用: amsams 发表于 2016-9-23 09:31
    我这个是上升沿捕获,没错。但我想在cpld做这样的改动:mosi增加寄存器,使效果变成,下降沿捕获发送,mi ...

    CPLD端,你写的是上升沿触发,才会造成紫色的线滞后其他颜色的线半个周期。你把它改成下降沿触发,波形就会和黄色的线一样的波形。
    点赞  2016-9-23 09:49
    引用: 1399866558 发表于 2016-9-23 09:49
    CPLD端,你写的是上升沿触发,才会造成紫色的线滞后其他颜色的线半个周期。你把它改成下降沿触发,波形就 ...

    上升沿触发的设置并不是在cpld中完成的,是stm32中的程序里的相性和极性设置的,这种设置使mosi和miso必须同时在上升沿和下降沿触发。但无论是哪种触发,最后一定后滞后半个SCK,所以我想在cpld中改一下这种效果,使紫色波形和绿色波形同步,就是黄色左移半个SCK,那紫色就会出现在黄色原来的位置,就没问题了
    点赞  2016-9-23 09:54
    如果CPLD的SPI用的是同步边沿检测的话,50M时钟实现18M的SPI通信是几乎不可能的,简单算一下就知道了 可靠的边沿检测需要两级寄存器来缓冲输入数据,也就是说,spi时钟到了CPLD中,被检测到后,至少也在2个时钟周期后了。 spi的工作模式是,主从机在相同的沿捕获和移出数据,比如时钟相位是0,则主机在上升沿捕获数据,在下降沿发送数据,从机也是这样,所以spi通信必须满足:从机在下降沿发送据后必须在下个上升沿之前到达主机,因为时钟是主机发出的,所以对主机没要求。 可以估算一下时序,主机在下降沿移出数据,布线延迟1.5cm就是1ns,算你3cm的布线2ns吧,到达cpld后,50M的主时钟,延迟2个时钟周期,就是40ns,加上CPLD的tco(从引脚进入信号)延迟,一般5ns是有的,这就47ns了,然后把数据打出寄存器,到达引脚,差不多8ns,这就55ns了,已经远远超过18M的半个时钟周期了,所以cpld在主机给出的时钟下降沿送出数据,是无论如何也无法在上升沿之前到达主机的 解决的办法只有: 1.提高cpld的工作时钟,降低边沿检测需要的时间 2.降低spi的发送速率,按照一般经验,cpld使用同步边沿检测实现spi从机,spi速度最好不要超过主时钟的1/5 3.cpld采用异步spi从机的设计,但异步电路设计需要小心的坑太多,自己看吧4.不使用标准的spi通信模式,即在上升沿捕获数据的同时,提前发送数据到主机,这样可以抢半个spi时钟周期的时间,但时序计算方式就不同了 本帖最后由 axellaw 于 2017-3-6 00:38 编辑
    点赞  2017-3-6 00:35
    刚做完stm32通过SPI发送FPGA接收,预分频数从256到2都没问题。FPGA发送stm32接收暂时不用,还没测试,您说的“50M时钟实现18M的SPI通信是几乎不可能的”,我这用的25M时钟都没问题。
    点赞  2017-3-7 06:41
    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
      写回复