内容介绍
内容介绍
项目介绍
本项目是基于STM32+iCE40的电赛训练平台,使用fpga和stm32制作的可调dds。
具体要求:
-
通过板上的高速DAC(10bits/最高125Msps)配合FPGA内部DDS的逻辑(最高48Msps),生成波形可调(正弦波、三角波、方波)、频率可调(DC-)、幅度可调的波形
- 生成模拟信号的频率范围为DC-5MHz,调节精度为1Hz
- 生成模拟信号的幅度为最大1Vpp,调节范围为0.1V-1V
- 在OLED上显示当前波形的形状、波形的频率以及幅度
- 利用板上旋转编码器和按键能够对波形进行切换、进行参数调节
设计思路
查阅原理图可知,DAC与FPGA相连,旋转编码器和屏幕与stm32连接。stm32通过spi向OLED屏幕通信,使之显示当前输出的波形信息。同时旋转编码器和按键用于控制改变DDS的波形。stm32储存波形的相关参数并通过spi发送给FPGA。
FPGA通过spi获得波形参数,通过相位累加器和查找表确定输出的波形信息。将波形信息发送到DAC实现数模转换。
软件流程
STM32完成屏幕的打印和按键信号的接收。通过spi向FPGA发送波形信息,通过控制FPGA来控制DAC的波形输出。FPGA通过spi读取到STM32发来的波形频率幅度信息后对将信息整合,通过查表获得波形的详细信息,控制DAC输出波形。
软件流程图:
硬件介绍
本项目使用了ICE40UP5K FPGA和STM32G031 MCU,通过板载LPC11U35下载器实现FPGA资源的下载。使用用硬禾电赛扩展板上的按键控制,板上的高速DAC输出DDS波形。
实现功能
可通过按键控制DDS波形和频率的变化。将当前波形,频率,幅度显示在OLED上。
OLED显示:
输出波形:
FPGA资源占用报告
代码片段
通过按键控制波形并通过spi输出到FPGA,代码如下:
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
uint8_t data[1];
uint8_t model_data[1];
if(GPIO_Pin==GPIO_PIN_6)
{
if (model == 3){
model = 0;
}
model++;
data[0] = model;
model_data[0] = 0b11111111;
HAL_SPI_Transmit(&hspi1,model_data,1,20);
HAL_SPI_Transmit(&hspi1,data,1,20);
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_6);
}
if(GPIO_Pin==GPIO_PIN_11)
{
freq++;
data[0] = freq;
model_data[0] = 0b11111100;
HAL_SPI_Transmit(&hspi1,model_data,1,20);
HAL_SPI_Transmit(&hspi1,data,1,20);
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_11);
}
if(GPIO_Pin==GPIO_PIN_12)
{
freq--;
data[0] = freq;
model_data[0] = 0b11111100;
HAL_SPI_Transmit(&hspi1,model_data,1,20);
HAL_SPI_Transmit(&hspi1,data,1,20);
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_12);
}
}
通过spi读取波形并改变代码如下:
always@(byte_rec)begin
case(flag_t)
2'b01: begin //01代表type改变
data_byte <= byte_rec;
type_ctrl_reg <= data_byte[1:0];
freq_ctrl_reg <= data_byte[1:0]*100*data_f;
data_f=data_f+2;
flag_t <= 2'b00;
end
2'b10: begin //10代表freq改变
data_byte <= byte_rec;
freq_ctrl_reg <= data_byte<<5;
flag_t <= 2'b00;
end
2'b11: begin //11代表amp改变
data_byte <= byte_receive;
amp_ctrl_reg <= byte_receive[3:0];
flag_t <= 2'b00;
end
default: begin //如果是00那就是判断接下来应该是哪个类型
if (byte_rec == 8'b11111111) begin
flag_t <= 2'b01;
end
else if (byte_rec == 8'b11111100) begin
flag_t <= 2'b10;
end
else if (byte_rec == 8'b11110000) begin
flag_t <= 2'b11;
end
end
endcase
end
dds实现和波形信息代码:
module dds(
input sys_clk, //The clock rate is same to sample rate, and we set it to SAMPLE_RATE.
input sys_rst_n,
input [1:0] wave_type, //The 00:Cos wave;01:Square wave;10:Trig wave;11:Saw wave.
input [31:0] wave_freq,
output reg [9:0] wave_dac
);
//MUX to choose suitable wave
wire [9:0] cos_dac;
wire [9:0] square_dac;
wire [9:0] trig_dac;
wire [9:0] saw_dac;
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
wave_dac <= 10'd0;
end else begin
case(wave_type)
2'b00: wave_dac <= cos_dac;
2'b01: wave_dac <= square_dac;
2'b10: wave_dac <= trig_dac;
2'b11: wave_dac <= saw_dac;
endcase
end
end
// Code below is designed to generate Cos wave
reg [27:0] dds_phase;
wire [27:0] dds_phase_add;
assign dds_phase_add = (wave_freq << 1) + (wave_freq >> 3) + (wave_freq >> 4) + (wave_freq >> 5) + (wave_freq >> 6) + (wave_freq >> 9) + (wave_freq >> 11) + (wave_freq >> 13); //wave_freq*2.2369384765625(10.00111100101010);
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
dds_phase <= 28'd0;
end else begin
dds_phase <= dds_phase + dds_phase_add;
end
end
lut u_lut(
.address(dds_phase[27:20]),
.cos(cos_dac)
);
//Code below is designed to generate Square wave
assign square_dac = {10{dds_phase[27]}};
//Code below is designed to generate Trig wave
assign trig_dac = dds_phase[27] ? ~dds_phase[26:17] : dds_phase[26:17];
//Code below is designed to generate Saw wave
assign saw_dac = dds_phase[27:18];
endmodule
module lut(
input [7:0] address,
output reg [9:0] cos
);
wire [1:0] section;
reg [5:0] lut_address;
reg [8:0] lut_cos;
assign section = address[7:6]; //Get the sections of cos wave to reduce memory
always@(address)begin
case(section)
2'b00: begin
lut_address = address[5:0];
cos = 9'h1ff + lut_cos;
end
2'b01: begin
lut_address = ~address[5:0];
cos = 9'h1ff + lut_cos;
end
2'b10: begin
lut_address = address[5:0];
cos = 9'h1ff - lut_cos;
end
2'b11: begin
lut_address = ~address[5:0];
cos = 9'h1ff - lut_cos;
end
endcase
end
always @(lut_address) begin
case(lut_address)
6'h0: lut_cos=9'h0;
6'h1: lut_cos=9'hC;
6'h2: lut_cos=9'h19;
6'h3: lut_cos=9'h25;
6'h4: lut_cos=9'h32;
6'h5: lut_cos=9'h3E;
6'h6: lut_cos=9'h4B;
6'h7: lut_cos=9'h57;
6'h8: lut_cos=9'h63;
6'h9: lut_cos=9'h70;
6'ha: lut_cos=9'h7C;
6'hb: lut_cos=9'h88;
6'hc: lut_cos=9'h94;
6'hd: lut_cos=9'hA0;
6'he: lut_cos=9'hAC;
6'hf: lut_cos=9'hB8;
6'h10: lut_cos=9'hC3;
6'h11: lut_cos=9'hCF;
6'h12: lut_cos=9'hDA;
6'h13: lut_cos=9'hE6;
6'h14: lut_cos=9'hF1;
6'h15: lut_cos=9'hFC;
6'h16: lut_cos=9'h107;
6'h17: lut_cos=9'h111;
6'h18: lut_cos=9'h11C;
6'h19: lut_cos=9'h126;
6'h1a: lut_cos=9'h130;
6'h1b: lut_cos=9'h13A;
6'h1c: lut_cos=9'h144;
6'h1d: lut_cos=9'h14E;
6'h1e: lut_cos=9'h157;
6'h1f: lut_cos=9'h161;
6'h20: lut_cos=9'h16A;
6'h21: lut_cos=9'h172;
6'h22: lut_cos=9'h17B;
6'h23: lut_cos=9'h183;
6'h24: lut_cos=9'h18B;
6'h25: lut_cos=9'h193;
6'h26: lut_cos=9'h19B;
6'h27: lut_cos=9'h1A2;
6'h28: lut_cos=9'h1A9;
6'h29: lut_cos=9'h1B0;
6'h2a: lut_cos=9'h1B7;
6'h2b: lut_cos=9'h1BD;
6'h2c: lut_cos=9'h1C3;
6'h2d: lut_cos=9'h1C9;
6'h2e: lut_cos=9'h1CE;
6'h2f: lut_cos=9'h1D4;
6'h30: lut_cos=9'h1D9;
6'h31: lut_cos=9'h1DD;
6'h32: lut_cos=9'h1E2;
6'h33: lut_cos=9'h1E6;
6'h34: lut_cos=9'h1E9;
6'h35: lut_cos=9'h1ED;
6'h36: lut_cos=9'h1F0;
6'h37: lut_cos=9'h1F3;
6'h38: lut_cos=9'h1F6;
6'h39: lut_cos=9'h1F8;
6'h3a: lut_cos=9'h1FA;
6'h3b: lut_cos=9'h1FC;
6'h3c: lut_cos=9'h1FD;
6'h3d: lut_cos=9'h1FE;
6'h3e: lut_cos=9'h1FF;
6'h3f: lut_cos=9'h1FF;
endcase
end
endmodule
主要难题
- 第一次学习stm32,学习使用stm32开发工具时经常出现问题,依靠网上教程解决。使用STM32cubemx时配置错误导致的问题在前期开发时消耗了大量的时间。
- 开始移植ssd1306驱动时完全使用四线spi协议导致无法实现通信,经过研究后改为三线手动片选控制后成功移植。
- stm32编写中断服务函数和spi发送函数时,由于没有调试器,只能通过屏幕大概了解程序执行情况,大大增加了开发难度。
- 由于stm32的encoder代码配置失败,只能采用三个按键控制,导致无法控制幅度。
- 第一次接触FPGA,学习了Verilog和FPGA开发流程,但是在使用radiant时依然遇到了大量的配置错误问题。观看直播视频和参考例程解决。
- FPGA实现DDS的方案思考,参考了互联网上实现案例。通过查表和相位累加器确定dac输出波形信息。
- FPGA移植spi时,由于没有调试器,无法明确知道fpga引脚接受到的信号和内部处理时的信息。参考Github上spi-slave代码实现通信,由于未知错误,只有单个信号控制可用。
未来计划
- 继续学习fpga,了解fpga高级应用。尝试实现示波器和risc-V软核移植。
- 继续学习stm32开发工具使用。尝试旋转编码器配置和OLED中文字库移植。
软硬件
附件下载
stm32.zip
stm32
dds.zip
fpga
团队介绍
caicaizi
评论
0 / 100
查看更多
猜你喜欢
基于小脚丫FPGA的电赛训练平台完成DDS任意波形发生器本项目利用小脚丫FPGA的电赛训练平台的高速DAC配合FPGA内部DDS的逻辑,生成波形可调(正弦波、三角波、方波)、频率可调、幅度可调的波形。
酷酷的胖~
2546
基于STM32+iCE40的电赛训练平台项目4 - DDS任意波形发生器/PC远程控制本项目使用STM32+iCE40核心板来实现DDS任意信号发生器,并借助‘基于STM32+iCE40的电赛训练平台'板卡上的DAC来实现波形的产生,并使用PC来进行远程控制波形、幅度、频率等信息
wyk
994
基于STM32+iCE40电赛训练平台的DDS任意波形发生器(本地控制)板卡主要包括单片机部分和FPGA部分。单片机部分主要用于显示、控制和复杂运算;FPGA主要用于数据的运输和处理。两者以SPI为桥梁进行通信。最终完成了硬禾所要求的《DDS任意波形发生器/本地控制》的要求。
zhiwu
1098