
你不给DA,AD的型号怎么写
DA,AD的实验我都做过,基于SPI接口的
给你个我调试通过的DA控制的程序吧,稍微简单点,型号LTC2624,串行输出,时钟5MHz,采用32位协议
module dac1(databus,clk,clr,serial_out,start,dac_cs,dac_clr,spi_ss_b,amp_cs,ad_conv,sf_ce0,init_b);
input clk,clr,start;//clk是DA控制器的时钟,也是DA的时钟没有在输出里面声明,需要在外部模块加入
input [11:0] databus;//数据总线
output serial_out,dac_cs,dac_clr,spi_ss_b,amp_cs,ad_conv,sf_ce0,init_b;//serial_out是输出给DA的串行数据,dac_cs是da的转换信号,一帧数据接受完毕后拉高,dac_clr是清空dac内部的寄存器,其他是SPI总线复用信号,可以忽略
reg [2:0] state,next_state;
parameter idle=3'b001;
parameter load2=3'b010;
parameter send=3'b100;
reg spi_ss_b;
reg amp_cs;
reg ad_conv;
reg sf_ce0;
reg init_b;
reg dac_cs;
reg dac_clr;
reg shift;
reg clear;
reg load;
reg [5:0] bit_counter;
reg [31:0] data_shfreg;
assign serial_out=data_shfreg[31];
always@(state or bit_counter or start)
begin
spi_ss_b=1;
amp_cs=1;
ad_conv=0;
sf_ce0=1;
init_b=1;
load=0;
shift=0;
clear=0;
next_state=state;
case(state)
idle: if(start==1)
begin
load=1;
next_state=load2;
end
load2: begin
load=1;
shift=1;
next_state=send;
end
send: if(bit_counter!=6'b100000)
shift=1;
else
begin
clear=1;
load=1;
next_state=load2;
end
default next_state=idle;
endcase
end
always @(posedge clk)
if(clr)
dac_clr<=0;
else
dac_clr<=1;
always @(posedge clk or posedge clr)
if(clr)state<=idle;else state <=next_state;
always @(posedge clk or posedge clr)
begin
if(clr)begin
data_shfreg<=0;
bit_counter<=0;
end
else
begin
if(load)
data_shfreg<={8'b11111111,4'b0011,4'b1111,databus[11:0],4'b1111};//32位协议格式
if(clear)bit_counter<=0;
else if(shift)bit_counter<=bit_counter+1;
if(shift)
data_shfreg<={data_shfreg[30:0],1'b1};
if(shift)
dac_cs<=0;
else
dac_cs<=1;
end
end
endmodule
always @(posedge spi_clk or negedge reset )
begin
if(cmd==2'b10)
begin
if(~reset)
begin
shifter_wr<=32'b0;
mosi<=1'bz;
wr_count<=1'b0;
end
else if (wr_count<=6'h1f)
begin
#2;
mosi<=shifter_wr[6'h1f-wr_count];
wr_count<=wr_count+6'h1;
end
else if (wr_count==6'h20)
wr_count<=6'b0;
end
end
用 quartus 160 编译,没啥问题,可以通过。
可能你编译用的verilog版本选用2001的试试吧。
verilog编译选用 verilog-2001,如下图:
还有最好这样写:
always @(posedge spi_clk or negedge reset )begin
if(~reset)
begin
shifter_wr<=32'b0;
mosi<=1'bz;
wr_count<=1'b0;
end
else
if(cmd == 2'b10)
begin
if (wr_count<=6'h1f)
begin
#2;
mosi<=shifter_wr[6'h1f-wr_count];
wr_count<=wr_count+6'h1;
end
else if (wr_count==6'h20)
wr_count<=6'b0;
end
end
把 if(cmd == 2'b10) 判断条件写在复位条件之后,不然会报错。
先看下SPI的时序吧,这个简单,但SPI时序不唯一,随便用一种就可以,然后stm32的程序网上很多,建议用模拟的先做测试,如果有示波器可以直接用STM32SPI模块,FPGA的话很灵活,知道了stm32的时序后,一配合STM32就可了,至于用Verilog还是VHDL看个人爱好了,网上搜Verilog SPI程序应该能找到好多,而且硬件描述语言和芯片基本无关,找来的代码直接贴上都能用。stm32找来代码一般不能用,要调试一下。Q308680190
你先用C实现,或找到C的驱动程序。然后把C改成verilog 。前提是你懂verilog语法。要再加点东西,比如采个电压用数码管显示出来。这完全是个本科毕设的水平了。
这个芯片用SPI驱动,FPGA作为SPI主设备。显然用单片机驱动更方便。
示例程序
void InitMcBSP0(void) //将McBSP0初始化为SPI
{
SPSA0=SPCR10_SUB;
SPSD0=0x00; //接收端复位RRST=0
SPSA0=SPCR20_SUB;
SPSD0=0x00; //发送端复位XRST=0
SPSA0=SPCR10_SUB;
SPSD0=0x1800; //CLKSTP=11
SPSA0=PCR0_SUB;
SPSD0=0x0A08; //CLKXM=1(主设备);CLKXP=0
SPSA0=RCR10_SUB;
SPSD0=0x00; //RWDLEN1=000,接收包长度为8
SPSA0=RCR20_SUB;
SPSD0=0x0001; //在BFSX信号上提供正确的建立时间
SPSA0=XCR10_SUB;
SPSD0=0x00; //XWDLEN1=000,发送包长度为8
SPSA0=XCR20_SUB;
SPSD0=0x0001; //在BFSX信号上提供正确的建立时间
SPSA0=SRGR10_SUB;
SPSD0=0x00FE; //为采样率时钟定义分频因子
SPSA0=SRGR20_SUB;
SPSD0=0x2000; //CLKSM=1,从CPU得到时钟;每个包传送时,激活BFSX信号
SPSA0=SPCR20_SUB;
SPSD0=0x0063; //发送端脱离复位XRST=1
SPSA0=SPCR10_SUB;
SPSD0|=0x0001; //接收端脱离复位RRST=1;采样率产生器脱离复位GRST=1
delay(256); //为使McBSP逻辑稳定,需等待两个采样率产生器时钟周期
}
二.HDn作为片选信号时DSP与MCP2510通信过程
21读程序
211 MCP2510读取过程
在读 *** 作开始时,CS引脚将被置为低电平。随后读指令和8 位地址码(A7 至 A0)将被依次送入MCP2510 。在接收到读指令和地址码之后, MCP2510 指定地址寄存器中的数据将被移出通过SO引脚进行发送。每一数据字节移出后,器件内部的地址指针将自动加一以指向下一地址。因此可以对下一个连续地址寄存器进行读 *** 作。通过该方法可以顺序读取任意个连续地址寄存器中的数据。通过拉高CS引脚电平可以结束读 *** 作。
编程时需注意问题:
1. SPI的读 *** 作是通过写 *** 作完成的。因此在DSP发送地址字节后,再发送一任意8位数据以产生接收时钟。
2. 在发送完任意8位数据后,DSP要有个延时,以等待写入DXR的数据从发送端移出,从而保证从2510输出的数据能够正确地被DSP接收。延时时间应大于采样率产生器输出的8个周期,最好长一些。
3. 由于SPI在发送数据的同时也在接收数据,所以在读取有效数据前(即在发送地址字节完毕后)要先清空接收缓冲器,否则可能会因为接收缓冲器溢出而无法接收有用的数据。可以通过读取3次(因为5402的McBSP有3个接收缓冲器)接收缓冲器DRR的值来实现清空缓冲器的 *** 作,读取之前要注意延时(等待地址字节发送完毕)。
212 示例程序
Uint16 ReadMCP2510(Uint16 Addr)
{
ChipSlctMCP2510(0); //打开片选
NOP;
NOP;
NOP;
//发送读指令
DXR10=READ_MCP2510;
SPSA0=SPCR20_SUB;
while(!(SPSD0&0x02)) //等待上一个数据发送完毕
{;}
//发送地址
DXR10=Addr;
SPSA0=SPCR20_SUB;
while(!(SPSD0&0x02)) //等待上一个数据发送完毕
{;}
delay(1000); //延时,等待地址字节从DX移出
//读取数据
Addr=DRR10; //读3次,清空缓冲器
Addr=DRR10;
Addr=DRR10;
DXR10=0; //发送任意数据,以便产生接收时钟
SPSA0=SPCR20_SUB;
while(!(SPSD0&0x02)) //等待上一个数据发送完毕
{;}
delay(1000); //延时,等待数据接收
Addr=DRR10; //第一次为无效数据
ChipSlctMCP2510(3);
return Addr;
}
22写程序
221 MCP2510写 *** 作
置CS引脚为低电平启动写 *** 作。 启动写指令后,地址码以及至少一个字节的数据被依次发送到MCP2510 。只要 CS 保持低电平,就可以对连续地址寄存器进行顺序写 *** 作。在SCK 引线上的上升沿,数据字节将从D0位开始依次被写入。如果CS 引脚在字节的8 位数据尚未发送完之前跳变到高电平,该字节的写 *** 作将被中止,而之前发送的字节已经写入。
编程时需注意问题:
1 2510如何区分指令、地址和数据?由于读写指令、地址字节和数据字节的值可能会一样,所以有必要通过一定的时序来将他们区分开来。经实验验证,2510应该是通过片选信号CS来区分这几个数据的,当CS从高变低后,第一个字节就是指令,哪怕上次没有正确的读写,只要将CS置1,然后再置0,就会重新开始一个指令的周期。
2 发送完数据字节后一定要有个延时来等待数据字节从DX引脚发送出去,之后才能将片选信号CS置1,否则无法正确写入数据。
222 示例程序
void WriteMCP2510(Uint16 Addr,Uint16 wrData)
{
ChipSlctMCP2510(0);
NOP;
NOP;
NOP;
DXR10=WRITE_MCP2510;
SPSA0=SPCR20_SUB;
while(!(SPSD0&0x02)) //等待上一个数据发送完毕
{;}
DXR10=Addr;
SPSA0=SPCR20_SUB;
while(!(SPSD0&0x02)) //等待上一个数据发送完毕
{;}
DXR10=wrData;
SPSA0=SPCR20_SUB;
while(!(SPSD0&0x02)) //等待上一个数据发送完毕
{;}
delay(1000);
ChipSlctMCP2510(3);
}
三.BFSX作为片选信号时DSP与MCP2510通信过程
由于要完成2510的读写 *** 作需要3个字节,所以采用BFSX引脚作为MCP2510的片选信号时需要将XCR1和RCR1中的XWDLEN1、RWDLEN1设置为100(24bit)。
由于发送接收字长度设置为24位,因此在发送过程中需要用到DXR2和DRR2寄存器,在此需要注意的一点就是,DXR2(DRR2)必须要比DXR1(DRR1)先初始化或读取。其中DXR2(DRR2)中存放的是24bit的高8位,DXR1(DRR1)中存放的是24bit的低16位。发送时DXR2中的数据首先发送,接收时数据首先存放到DRR2中,因此DXR2(DRR2)中存放指令字节,DXR1(DRR1)中由高到低存放地址和数据。
下面为一个简单的调试程序。
Uint16 Debug24bit( )
{
int i;
DXR20=0x02; //写指令
DXR10=0x0F01; //0F为CANCTRL地址,01为待写入的数据
delay(3000); //延时,等待发送完毕
i=DRR10; //清空接收缓冲器
i=DRR10;
i=DRR10;
DXR20=0x03; //读指令
DXR10=0x0F00; //0F为CANCTRL地址,00用于读取数据
delay(3000); //延时,等待接收完毕
i=DRR10&0x00FF; //DRR10低8位为有用数据
return i;
}
四. 通信时MCP2510的初始化
411 确定时间份额
计算公式:
时间份额TQ定义为:TQ = 2(BaudRate + 1)TOSC
其中,BaudRate 是由 CNF1BRP<5:0> 表征的二进制数。
标称位时间 = TQ (Sync_Seg + Prop_Seg +Phase_Seg1 + Phase_Seg2)
- 同步段(Sync_Seg)
- 传播时间段(Prop_Seg)
- 相位缓冲段1 (Phase_Seg1)
- 相位缓冲段2 (Phase_Seg2)
假设每个标称位包含N个时间份额TQ,则根据以上公式有:1/100K = NTQ
现设定分频值BaudRate为1,根据以上公式计算,得出在4MHz时钟时,要实现100Kbps的波特率每个标称位包含个10时间份额TQ,在N满足要求的情况下BaudRate还可以设置为其他值,由MCP2510的手册得知的TQ数量N应在6-25之间。然而在满足这个前提下,应尽量使TQ的时间短一些,即一个标称位的时间份额数量N多一些,这样选择采样点位置时具有更好的分辨率。
412 设置时间段和采样点
在确定了一个标称位包含的时间份额数量后,还需要对各个时间段包含的时间份额进行分配,以确定采样点的位置。位的采样时刻取决于系统参数,通常应发生在位时间的60-70%处。同时,同步段的时间份额为1 TQ,TDELAY典型值为1-2TQ。因此时间份额分配如下:
(Sync_Seg + Prop_Seg +Phase_Seg1 + Phase_Seg2)=(1+2+3+4)
413 确定同步跳转宽度和采样次数
根据规则,SJW最大值 为4TQ。然而通常情况下,只有当不同节点的时钟发生不够精确或不稳定时,例如采用陶瓷谐振器时,才需要较大的SJW。一般情况下, SJW取1即可满足要求。
以上就是关于求verilog的一段代码全部的内容,包括:求verilog的一段代码、Verilog al程序运行错误 求各位大神讲一下原因和怎样修改呀、STM32和FPGA通过SPI进行通讯等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)