用FPGA做了一个SPI接口控制器,用示波器观察,CS,convst/rd,SDI,BUSY,CLK到片脚信号正常,但SDO无信号输出?
有谁知道SDI数据应在SPI CLK时钟的上升沿改变还是下降沿改变,需要每次单通道采集一次数据,应设置MODE几方式较好?
Harson:
Hi, Lili
Mode 的选择请考虑几个方面:
1、单端采样,还是差分采样
2、SDOA单输出还是SDOA & SDOB同时输出?
可以看下Special Mode II是否适合你的应用。
从Figure 39 看,SDI数据是在CLK的下降沿有效,所以在上升沿改变。
Andrew Wu:
初步怀疑是SPI配置的问题,请问楼主可否将SPI的配置程序以及示波器波形上传?datasheet中显示SDI数据是在CLK的上升沿改变的。每个应用模式都可以满足您所说的每次单通道采集数据一次的要求,只是在half clock mode 和full clock mode需要的时钟不同,在half clock mode下需要40个时钟才能输出一次SDO,2us完成一次完整的读数据,而full clock mode只需要一般的时间。
lili zhang1:
今天根据指点,我做了以下实验,现象很奇怪!
我的电路要求是实现两路正负+-5V单端输入的测试,SDOA输出,用的SPI CLK为4MHz,Special Mode II读,参照Figure 36,SDOA采用上升沿读数,结果在指定的位置读数始终为0,图如下:
3为CS信号,1为RD/CONVST信号,2为SDI信号,4为SDOA信号,整个CS周期为60个SPI CLK时钟。
CONFIG的配置为0X1140,即M0=0,M1=1,SR=1,PDE=1,CID=0,R[1:0]=01,C[1:0]=00,
在SPICLK的第44个脉冲上升沿开始读SDOA的数据,结果如上图三分之二后显示一样,始终为0,前两个20脉冲周期有数据输出,但不知哪个正确?
请大侠指教了!!
lili zhang1:
回复 lili zhang1:
现将SPI的VHDL代码贴上,请指教!!!
— spi_read.vhd
LIBRARY ieee;USE ieee.std_logic_1164.ALL;USE ieee.std_logic_unsigned.ALL;——————————————————————– I/O名称及方向设定 ——————————————————————–ENTITY spi_60 IS PORT ( clock : IN STD_LOGIC; –系统时钟 clk : IN STD_LOGIC; –SPI总线时钟输入 trg : IN STD_LOGIC; –控制转换开始使能,'1'有效 sdo : IN STD_LOGIC; –串行输入数据 config : IN STD_LOGIC_VECTOR(15 DOWNTO 0); –并行输入数据 data : OUT STD_LOGIC_VECTOR(17 DOWNTO 0); –并行输出数据 ch2bit+data16bit ad_rd_convst : OUT STD_LOGIC; –输出 flag : OUT STD_LOGIC; –输出 sck : OUT STD_LOGIC; –输出时钟 scs : OUT STD_LOGIC; –片选信号,'1'有效 sdi : OUT STD_LOGIC); –串行输出数据END spi_60;——————————————————————– 功能描述 ——————————————————————–ARCHITECTURE spi_60_bh OF spi_60 IS CONSTANT clk_n : INTEGER := 16; –数据发送位数 SIGNAL shift_wr : STD_LOGIC_VECTOR(15 DOWNTO 0); –并行输入数据缓存 SIGNAL shift_rd : STD_LOGIC_VECTOR(17 DOWNTO 0); –并行输出数据缓存 ch2bit+data16bit SIGNAL spi_en : STD_LOGIC; –片选信号缓存 SIGNAL din : STD_LOGIC; –串行输出数据缓存 SIGNAL dout : STD_LOGIC; –串行输入数据缓存 SIGNAL ad_rd_cvt : STD_LOGIC; SIGNAL flag1 : STD_LOGIC;
BEGIN
PROCESS (trg, clock) VARIABLE clk_cnt : INTEGER RANGE 0 TO 40;–40 VARIABLE spi_state : STD_LOGIC_VECTOR(6 DOWNTO 0); VARIABLE trg_state : STD_LOGIC; BEGIN IF (trg = '0') THEN spi_en <= '0'; din <= '0'; shift_wr <= (OTHERS => '0'); shift_rd <= (OTHERS => '0'); clk_cnt := 0; ad_rd_cvt <='0'; flag1 <= '0'; spi_state := "0000000"; ELSIF rising_edge(clock) THEN———-ad8363 ===>special read mode II (half-clock mode only) CASE (spi_state) IS WHEN "0000000" => –检测 IF (clk = '1') THEN——-write shift_wr <= config; spi_en <= '1'; flag1 <= '1'; spi_state := "0000001"; END IF; WHEN "0000001" => –检测CLK为'0' IF (clk = '0') THEN din <= '0'; spi_state := "0000010"; END IF; WHEN "0000010" => –检测CLK为'1'no.1 IF (clk = '1' ) THEN ad_rd_cvt <='1'; spi_state := "0000011"; END IF; WHEN "0000011" => –检测CLK为'0' IF (clk = '0') THEN ad_rd_cvt <='0'; — din <= '0'; spi_state := "0000100"; END IF; WHEN "0000100" => –pluse 2 IF (clk = '1' ) THEN spi_state := "0000101"; END IF; WHEN "0000101" => –检测CLK为'0' IF (clk = '0') THEN — din <= '0'; spi_state := "0000110"; END IF; WHEN "0000110" => –检测CLK为'1' p3 IF (clk = '1' ) THEN spi_state := "0000111"; END IF; WHEN "0000111" => –检测CLK为'0' IF (clk = '0') THEN — din <= '0'; spi_state := "0001000"; END IF; WHEN "0001000" => —p 4 IF (clk = '1' ) THEN din <= shift_wr(15); spi_state := "0001001"; END IF; WHEN "0001001" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0001010"; END IF; WHEN "0001010" => –判断是否–p5 IF (clk = '1' ) THEN din <= shift_wr(14); spi_state := "0001011"; END IF; WHEN "0001011" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0001100"; END IF; WHEN "0001100" => –判断是否-p6 IF (clk = '1') THEN din <= shift_wr(13); spi_state := "0001101"; END IF; WHEN "0001101" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0001110"; END IF; WHEN "0001110" => –检测CLK为'1'–p7 IF (clk = '1' ) THEN din <= shift_wr(12); spi_state := "0001111"; END IF; WHEN "0001111" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0010000"; END IF; WHEN "0010000" => –判断–p8 IF (clk = '1' ) THEN din <= shift_wr(11); spi_state := "0010001"; END IF; WHEN "0010001" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0010010"; END IF; WHEN "0010010" => –检测CLK为'1'–p9 IF (clk = '1' ) THEN din <= shift_wr(10); spi_state := "0010011"; END IF; WHEN "0010011" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0010100"; END IF; WHEN "0010100" => –p10 IF (clk = '1' ) THEN din <= shift_wr(9); spi_state := "0010101"; END IF; WHEN "0010101" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0010110"; END IF; WHEN "0010110" => –判断是否–p11 IF (clk = '1' ) THEN din <= shift_wr(8); spi_state := "0010111"; END IF; WHEN "0010111" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0011000"; END IF; WHEN "0011000" => –判断是否—p12 IF (clk = '1') THEN din <= shift_wr(7); spi_state := "0011001"; END IF; WHEN "0011001" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0011010"; END IF; WHEN "0011010" => –检测CLK为'1'–p13 IF (clk = '1' ) THEN din <= shift_wr(6); spi_state := "0011011"; END IF; WHEN "0011011" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0011100"; END IF; WHEN "0011100" => —p14 IF (clk = '1' ) THEN din <= shift_wr(5); spi_state := "0011101"; END IF; WHEN "0011101" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0011110"; END IF; WHEN "0011110" => –判断是否—p15 IF (clk = '1' ) THEN din <= shift_wr(4); spi_state := "0011111"; END IF; WHEN "0011111" => –检测CLK为'0'===0x1F IF (clk = '0') THEN spi_state := "0100001"; END IF; WHEN "0100001" => –判断是否—p16 IF (clk = '1') THEN din <= shift_wr(3); spi_state := "0100010"; end if; WHEN "0100010" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0100011"; END IF; WHEN "0100011" => –检测CLK为'1'–p17 IF (clk = '1' ) THEN din <= shift_wr(2); spi_state := "0100100"; END IF; WHEN "0100100" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0100101"; END IF; WHEN "0100101" => —————-p18 IF (clk = '1' ) THEN din <= shift_wr(1); spi_state := "0100110"; END IF; WHEN "0100110" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0100111"; END IF; WHEN "0100111" => –判断是否–p19 IF (clk = '1' ) THEN din <= shift_wr(0); spi_state := "0101000"; END IF; WHEN "0101000" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0101001"; END IF; WHEN "0101001" => –判断是否—p20 IF (clk = '1') THEN din <= '0'; spi_state := "0101010"; end if; WHEN "0101010" => –判断是否 IF (clk = '0') THEN spi_state := "0101011"; end if;
—————————————————————————- WHEN "0101011" => –检测CLK为'1' 第21个SPI时钟 read_sdo IF (clk = '1') THEN ad_rd_cvt <='1'; spi_state := "0101100"; END IF; WHEN "0101100" => –检测CLK为'0' IF (clk = '0') THEN ad_rd_cvt <='0'; spi_state := "0101101"; END IF; WHEN "0101101" => –检测CLK为'1' —pluse 2 IF (clk = '1' ) THEN spi_state := "0101110"; END IF; WHEN "0101110" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "0101111"; END IF; WHEN "0101111" => –检测CLK为'1'–p3 IF (clk = '1' ) THEN spi_state := "0110000"; END IF; WHEN "0110000" => –检测CLK为'0'===0x30 IF (clk = '0') THEN spi_state := "0110001"; END IF; WHEN "0110001" => –检测CLK为'1'–p4 IF (clk = '1') THEN spi_state := "0110010"; END IF; WHEN "0110010" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(15); spi_state := "0110011"; END IF; WHEN "0110011" => –p5 IF (clk = '1') THEN spi_state := "0110100"; END IF; WHEN "0110100" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(14); spi_state := "0110101"; END IF; WHEN "0110101" => –p6 IF (clk = '1') THEN spi_state := "0110110"; END IF; WHEN "0110110" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(13); spi_state := "0110111"; END IF; WHEN "0110111" => –检测CLK为'1'–p7 IF (clk = '1') THEN —read spi_state := "0111000"; END IF; WHEN "0111000" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(12); spi_state := "0111001"; END IF; WHEN "0111001" => –检测CLK为'1'–p8 IF (clk = '1' ) THEN spi_state := "0111010"; END IF; WHEN "0111010" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(11); spi_state := "0111011"; END IF; WHEN "0111011" => –检测CLK为'1'–p9 IF (clk = '1' ) THEN spi_state := "0111100"; END IF; WHEN "0111100" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(10); spi_state := "0111101"; END IF; WHEN "0111101" => –检测CLK为'1'–p10 IF (clk = '1') THEN spi_state := "0111110"; END IF; WHEN "0111110" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(9); spi_state := "0111111"; END IF; WHEN "0111111" => –判断–p11 IF (clk = '1') THEN spi_state := "1000000"; END IF; WHEN "1000000" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(8); spi_state := "1000001"; END IF; WHEN "1000001" => –检测CLK为'1'–p12 IF (clk = '1' ) THEN spi_state := "1000010"; END IF; WHEN "1000010" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(7); spi_state := "1000011"; END IF; WHEN "1000011" => –检测CLK为'1'–p13 IF (clk = '1') THEN spi_state := "1000100"; END IF; WHEN "1000100" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(6); spi_state := "1000101"; END IF; WHEN "1000101" => –判断–p14 IF (clk = '1') THEN spi_state := "1000110"; END IF; WHEN "1000110" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(5); spi_state := "1000111"; END IF; WHEN "1000111" => –检测CLK为'1'–p15 IF (clk = '1' ) THEN spi_state := "1001000"; END IF; WHEN "1001000" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(4); spi_state := "1001001"; END IF; WHEN "1001001" => –检测CLK为'1'–p16 IF (clk = '1') THEN spi_state := "1001010"; END IF; WHEN "1001010" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(3); spi_state := "1001011"; END IF; WHEN "1001011" => –判断–p17 IF (clk = '1') THEN spi_state := "1001100"; END IF; WHEN "1001100" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(2); spi_state := "1001101"; END IF; WHEN "1001101" => –判断–p18 IF (clk = '1') THEN spi_state := "1001110"; END IF; WHEN "1001110" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(1); spi_state := "1001111"; END IF; WHEN "1001111" => –判断–p19 IF (clk = '1') THEN spi_state := "1010000"; END IF; WHEN "1010000" => –检测CLK为'0' IF (clk = '0') THEN — din <= shift_wr(0); spi_state := "1010001"; END IF; WHEN "1010001" => –判断–p20 IF (clk = '1') THEN spi_state := "1010010"; END IF; WHEN "1010010" => –判断 IF (clk = '0') THEN spi_state := "1010011"; END IF; —————————————————————————- WHEN "1010011" => –检测CLK为'1' 第41个SPI时钟 read_sdo IF (clk = '1') THEN spi_state := "1010100"; END IF; WHEN "1010100" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1010101"; END IF; WHEN "1010101" => –检测CLK为'0'–p42 IF (clk = '1' ) THEN shift_rd(17) <= dout; spi_state := "1010110"; END IF; WHEN "1010110" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1010111"; END IF; WHEN "1010111" => –检测CLK为'1'–p43 IF (clk = '1' ) THEN shift_rd(16) <= dout; spi_state := "1011000"; END IF; WHEN "1011000" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1011001"; END IF; WHEN "1011001" => –检测CLK为'1'–p44 IF (clk = '1') THEN shift_rd(15) <= dout; spi_state := "1011010"; END IF; WHEN "1011010" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1011011"; END IF; WHEN "1011011" => –p45 IF (clk = '1') THEN shift_rd(14) <= dout; spi_state := "1011100"; END IF; WHEN "1011100" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1011101"; END IF; WHEN "1011101" => ————–p46 IF (clk = '1') THEN shift_rd(13) <= dout; spi_state := "1011110"; END IF; WHEN "1011110" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1011111"; END IF; WHEN "1011111" => –检测CLK为'1'—p47 IF (clk = '1') THEN —read shift_rd(12) <= dout; spi_state := "1100000"; END IF; WHEN "1100000" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1100001"; END IF; WHEN "1100001" => –检测CLK为'1'—p48 IF (clk = '1' ) THEN shift_rd(11) <= dout; spi_state := "1100010"; END IF; WHEN "1100010" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1100011"; END IF; WHEN "1100011" => –检测CLK为'1'—-p49 IF (clk = '1' ) THEN shift_rd(10) <= dout; spi_state := "1100100"; END IF; WHEN "1100100" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1100101"; END IF; WHEN "1100101" => –检测CLK为'1'–p50 IF (clk = '1') THEN shift_rd(9) <= dout; spi_state := "1100110"; END IF; WHEN "1100110" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1100111"; END IF; WHEN "1100111" => –判断—p51 IF (clk = '1') THEN shift_rd(8) <= dout; spi_state := "1101000"; END IF; WHEN "1101000" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1101001"; END IF; WHEN "1101001" => –检测CLK为'1'–p52 IF (clk = '1' ) THEN shift_rd(7) <= dout; spi_state := "1101010"; END IF; WHEN "1101010" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1101011"; END IF; WHEN "1101011" => –检测CLK为'1'–p53 IF (clk = '1') THEN shift_rd(6) <= dout; spi_state := "1101100"; END IF; WHEN "1101100" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1101101"; END IF; WHEN "1101101" => –判断是—p54 IF (clk = '1') THEN shift_rd(5) <= dout; spi_state := "1101110"; END IF; WHEN "1101110" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1101111"; END IF; WHEN "1101111" => –检测CLK为'1'–p55 IF (clk = '1' ) THEN shift_rd(4) <= dout; spi_state := "1110000"; END IF; WHEN "1110000" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1110001"; END IF; WHEN "1110001" => –检测CLK为'1'–p56 IF (clk = '1') THEN shift_rd(3) <= dout; spi_state := "1110010"; END IF; WHEN "1110010" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1110011"; END IF; WHEN "1110011" => –判断是—p57 IF (clk = '1') THEN shift_rd(2) <= dout; spi_state := "1110100"; END IF; WHEN "1110100" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1110101"; END IF; WHEN "1110101" => –判断是–p58 IF (clk = '1') THEN shift_rd(1) <= dout; spi_state := "1110110"; END IF; WHEN "1110110" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1110111"; END IF; WHEN "1110111" => –判断是—p59 IF (clk = '1') THEN shift_rd(0) <= dout; spi_state := "1111000"; END IF; WHEN "1111000" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1111001"; END IF; WHEN "1111001" => –判断—-p60 IF (clk = '1') THEN spi_state := "1111010"; END IF; WHEN "1111010" => –检测CLK为'0' IF (clk = '0') THEN spi_state := "1111011"; END IF; WHEN "1111011" => –判断是否发送完毕 IF (trg = '1') THEN flag1 <= '0'; spi_state := "1111011"; ELSE spi_state := "0000000"; END IF; ————————————————————- WHEN OTHERS => flag1 <= '0'; spi_state := "1111011"; END CASE; END IF; END PROCESS;——————————————————————– 输入/输出 ——————————————————————– scs <= not spi_en; data <= shift_rd; sdi <= din WHEN (spi_en = '1') ELSE '0'; sck <= clk WHEN (spi_en = '1') ELSE '0'; ad_rd_convst <= ad_rd_cvt; flag <= flag1;—转换过程标志 1–正在转换 0–完毕
dout <= sdo ;
END spi_60_bh;
lili zhang1:
回复 lili zhang1:
大侠都有事不在吗?请指教了,多谢了!!!
Andrew Wu:
回复 lili zhang1:
我认为中间20个时钟读出的数据位本次转换的数据,你先确认一下中间20个时钟周期读出的数据是否符合你的输入信号。另外你在一个CS信号周期convst和RD信号有两个,所以进行了两次转换和两次读取,而你的输出也正好为两组数据。所以,我认为你的ADC已经工作了,请确认一下转换结果和你的输入信号是否一致。谢谢!
lili zhang1:
回复 Andrew Wu:
现将RD和CONVST分别加,第一个20SPICLK加RD,将SDI数据读入AD的配置寄存器,第二个20SPICLK加CONVST,AD开始转换,观察BUSY波形完成,第三个20SPICLK加RD,读出SDOA的数据,结果值不定.数据是在RD信号结束后立即开始读,CID=1.配置字0X0060,0X0160,0X1160等都试过.不行!请指教了,多谢!!!
lili zhang1:
回复 lili zhang1:
求救,真没招了,折腾了一个月了,还是解决不了,那位大侠好心给个样例程序吧,否则只好暂时放弃了.,
Andrew Wu:
回复 lili zhang1:
上一下你的原理图吧。另外你的输入信号是+5V和-5V不变的吗?你先别急,遇到问题也要一步一步来解决。
lili zhang1:
回复 Andrew Wu:
用的是ADS8363EVM,如下图,通过3个插座与母板连接,FPGA引脚与J3的1脚CS、3脚clk、7脚RD、11脚sdi、13脚sdoa、15脚busy、17脚convst相连,AD口接
至J1的16脚cha0、14脚cha1、12脚cha2、10脚cha3,输入电压范围为-5V~+5V,现有几个问题不明:
1、SDI数据写入config寄存器的起始标志是不是RD信号的结束下降沿,还是CS以为低有效,就在clk的时钟下自动写入?
2、RD在读取SDOA时相对clk的时钟是否是第一个上升沿开始到第二个上升沿结束,在第二个clk的下降沿开始读取MSB16位,以后延续在Clk的下降沿读数?
3、config_reg的R[1:0]是否在第一次20个clk时钟中必须写01,然后再在第二个20个clk时钟中改为00,才不影响第三个20个clk时钟中的SDOA结果输出?
4、RD和CONVST两个信号可否分别使用,不必合成一个?
请解惑,多谢了!!!