【发布时间】:2013-01-03 16:37:36
【问题描述】:
我需要进行持续的 SPI 通信以从我拥有的双通道 ADC 读取值,并且为此编写了一个状态机。但是,它似乎没有进入读取第二个通道的状态,我不知道为什么。这是 VHDL...
SPI_read: process (mclk)
--command bits: Start.Single.Ch.MSBF....
constant query_x: unsigned(ADC_datawidth-1 downto 0) := "11010000000000000"; -- Query ADC Ch0 ( inclinometer x-axis)
constant query_y: unsigned(ADC_datawidth-1 downto 0) := "11110000000000000"; -- Query ADC Ch1 ( inclinometer y-axis)
begin
if rising_edge(mclk) then
-- when SPI is not busy, change state and latch Rx data from last communication
if (SPI_busy = '0') then
case SPI_action is
when SETUP =>
SPI_pol <= '0'; -- Clk low when not active
SPI_pha <= 1; -- First edge is half an SCLK period after CS activated
SPI_action <= READ_X;
when READ_X =>
SPI_Tx_buf <= query_x; -- Load in command
y_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READ_Y;
when READ_Y =>
SPI_Tx_buf <= query_y; -- Load in command
x_data <= "00000" & SPI_Rx_buf(11 downto 1);
SPI_send <= '1';
SPI_action <= READ_X;
end case;
else
SPI_send <= '0'; -- Deassert send pin
end if;
end if;
end process SPI_read;
命令被发送到 Tx 缓冲区,最后接收到的数据的值被写入一个信号,该信号输出到一些七段显示器。需要一个来自 SPI_send 的脉冲来启动传输,启动时,SPI_busy 设置为高电平,直到传输完成。
现在它只会通过 SPI 发送 query_x,我可以知道这一点,因为我可以在示波器上看到它。然而,有趣的是,它向两个显示器输出相同的值,这让我认为它仍在进入它的 READ_Y 状态,但没有改变它输出的 Tx 数据。
我已经盯着这段代码看了好几个小时了,但我想不通。有时一双新鲜的眼睛会让生活更轻松,所以如果你发现了什么,请告诉我。 另外,我非常愿意接受更好的处理方法的建议,我只是在学习 VHDL,所以我什至不确定我是否以正确的方式做事!
【问题讨论】:
-
我没有看到 tx 部分的代码和状态声明。一个建议是坚持基本的一流程状态机模板。使busyX 和busyY 状态最简单。
-
另外,当您学习 HDL 仿真时,它是您的朋友,它使此类调试问题变得非常容易。
-
对不起,应该说SPI主控是一个组件,它在发送/接收时返回SPI_busy。这只是我的顶层设计中的一个过程,因此不想包含太多可能无关紧要的内容。 SPI_action 以“SETUP”状态开始,然后一旦运行就不会返回那里。不过,我不确定我理解你最后一句话的意思。
-
你真的应该模拟这个设计,它会告诉你每个信号在一个交易周期中的状态。我看不出代码本身有任何明显错误,但这可能是关于 spi_writer 模块如何工作的问题或错误假设,或者只是一个错误。即从SPI_send 变高到busy 变高需要多少个时钟周期?是否所有东西都在同一个时钟域中运行?
-
我自己编写了SPI组件并完全模拟了它。但你是对的,我现在应该模拟它。但是,是的,一切都超出了主时钟。我只是不确定这是否是“等待完成”类型行为的正确方法。我要做的就是在 SPI_send 上发送一个脉冲,该脉冲需要比传输周期短,然后等待 SPI_busy 被取消断言。不过,我很难在任何地方找到任何关于这种行为的文章。