bandicam 2021-05-15 17-24-15-216
`本帖最后由PCB62304753 于 2021-5-15 18:42 编辑
前言:FPGA的市场一直在外国的三个巨头的手续牢牢把持,很高兴国内能有高云这样的企业去做,去弥补国内市场的空白,高云这块小蜜蜂fpga内置一个m3的硬核,对于fpga设计是一个很好的补充,很多设计可以利用mcu与fpga互为补充进行设计。因为平时没啥时间,还想尽可能的去体验一下高云的MCU硬核,所以设计了这样一个题目,按照架构也可以很容易的做一个任意信号发生器,有时间可以继续完善一下,当然这是后话了。之前只是简单的使用过altera的一款芯片,开发经验不足,望大家多多指教。
设计思路: 整个设计包含如下几个部分: 1.方波输出 2.按键输入 3.oled显示 这里我把它分为两个部分。FPGA部分驱动方波生成,MCU部分驱动按键与oled显示。两者直接通过AHB总线进行通信。 流程为:oled显示当前频率,当监测到有按键操作的时候去处理按键,同时通过AHB总线将设置的频率发送给fpga部分。
MCU程序设计: 这里用0xA0000000地址去存放需要发给fpag的频率(此处的数据是按照32位溢出以及27MHz时钟转换出来的累加值), 1.判断三个按键状态。当按键按下时,先消抖,然后等待按键抬起。按键功能分别是:移动光标,减少光标所在处频率的数值,增加光标所在处频率的数值。 2.把转换完的频率写入0xA0000000地址(转换式为频率*2^32/27000000)。 3.修改屏幕上的显示。
- uint32_t freq = 0; //频率
- uint8_t place = 0; //选中
- SystemInit();
- GPIOInit();
- OLED_Init(); //初始化OLED
- OLED_Clear();
- while(1)
- {
- if((GPIO_ReadBits(GPIO0)&GPIO_Pin_2) == 0)
- {
- delay_ms(20);
- while((GPIO_ReadBits(GPIO0)&GPIO_Pin_2) == 0){}
- freq += reduce_freq[place];
- }
- if((GPIO_ReadBits(GPIO0)&GPIO_Pin_3) == 0)
- {
- delay_ms(20);
- while((GPIO_ReadBits(GPIO0)&GPIO_Pin_3) == 0){}
- if(freq > reduce_freq[place])
- freq -= reduce_freq[place];
- else
- freq = 0;
- }
- if((GPIO_ReadBits(GPIO0)&GPIO_Pin_4) == 0)
- {
- delay_ms(20);
- while((GPIO_ReadBits(GPIO0)&GPIO_Pin_4) == 0);
- place++;
- if(place > 7)
- place = 0;
- }
- *((uint32_t *)0xA0000000) = freq*159.0728628148148148; //把频率给fpga
- {
- OLED_ShowChar(16+8*0, 3, '0'+freq/10000000%10, place==7?1:0);
- OLED_ShowChar(16+8*1, 3, '0'+freq/1000000%10, place==6?1:0);
- OLED_ShowChar(16+8*2, 3, ',',0);
- OLED_ShowChar(16+8*3, 3, '0'+freq/100000%10, place==5?1:0);
- OLED_ShowChar(16+8*4, 3, '0'+freq/10000%10, place==4?1:0);
- OLED_ShowChar(16+8*5, 3, '0'+freq/1000%10, place==3?1:0);
- OLED_ShowChar(16+8*6, 3, ',',0);
- OLED_ShowChar(16+8*7, 3, '0'+freq/100%10, place==2?1:0);
- OLED_ShowChar(16+8*8, 3, '0'+freq/10%10, place==1?1:0);
- OLED_ShowChar(16+8*9, 3, '0'+freq/1%10, place==0?1:0);
- OLED_ShowChar(16+8*10, 3 ,'H',0);
- OLED_ShowChar(16+8*11, 3 ,'z',0);
- }
- }
复制代码
FPGA程序设计: 分为top、硬核、AHB解析、方波发生。 top:主要是实例化各个模块。 硬核部分:使用了gpio与AHB2 Master两部分,ip核,使用软件配置起来非常方便。
AHB解析部分:在AHB的0位置处,设计了一个reg_freq寄存器,为32位,用于接收MCU发来的方波的频率。
- `timescale 100 ps/100 ps
- module Gowin_AHB_Multiple
- (
- output [31:0] freq,
- output wire [31:0] AHB_HRDATA,
- output wire AHB_HREADY,
- output wire [ 1:0] AHB_HRESP,
- input wire [ 1:0] AHB_HTRANS,
- input wire [ 2:0] AHB_HBURST,
- input wire [ 3:0] AHB_HPROT,
- input wire [ 2:0] AHB_HSIZE,
- input wire AHB_HWRITE,
- input wire AHB_HMASTLOCK,
- input wire [ 3:0] AHB_HMASTER,
- input wire [31:0] AHB_HADDR,
- input wire [31:0] AHB_HWDATA,
- input wire AHB_HSEL,
- input wire AHB_HCLK,
- input wire AHB_HRESETn
- );
- //The AHB BUS is always ready
- assign AHB_HREADY = 1'b1; //ready signal, slave to MCU master
- //Response OKAY
- assign AHB_HRESP = 2'b0;//response signal, slave to MCU master
- //Define Reg for AHB BUS
- reg [31:0] ahb_address;
- reg ahb_control;
- reg ahb_sel;
- reg ahb_htrans;
- always @(posedge AHB_HCLK or negedge AHB_HRESETn)
- begin
- if(~AHB_HRESETn)
- begin
- ahb_address <= 32'b0;
- ahb_control <= 1'b0;
- ahb_sel <= 1'b0;
- ahb_htrans <= 1'b0;
- end
- else //Select The AHB Device
- begin //Get the Address of reg
- ahb_address <= AHB_HADDR;
- ahb_control <= AHB_HWRITE;
- ahb_sel <= AHB_HSEL;
- ahb_htrans <= AHB_HTRANS[1];
- end
- end
- wire write_enable = ahb_htrans & ahb_control & ahb_sel;
- wire read_enable = ahb_htrans & (!ahb_control) & ahb_sel;
- //The register of Multiple AHB bus
- reg [32:0] reg_freq;
- //write data to AHB bus
- always @(posedge AHB_HCLK or negedge AHB_HRESETn)
- begin
- if(~AHB_HRESETn)
- begin
- reg_freq <= 32'b0;
- end
- else if(write_enable)
- begin
- case (ahb_address[15:0])
- 16'h0000: reg_freq <= AHB_HWDATA[31:0];
- endcase
- end
- end
- //register address
- reg [31:0] ahb_rdata;
- always @(*)
- begin
- if(read_enable) //read cmd
- begin
- case (ahb_address[15:0])
- 32'h0000: ahb_rdata = reg_freq;
- default:ahb_rdata = 32'hFFFFFFFF;
- endcase
- end
- else
- begin
- ahb_rdata = 32'hFFFFFFFF;
- end
- end
- assign AHB_HRDATA = ahb_rdata;
- assign freq = reg_freq;
- endmodule
复制代码
方波发生部分:就是一个32位累加器,通过修改单次累加数据的大小来控制波形的周期
- module wave (
- input sys_clk,
- input reset_n,
- input [31:0] freq,
- output wave_out
- );
- reg [31:0] phase_acc;
- always @(posedge sys_clk) phase_acc <= phase_acc + freq;
- wire [31:0] phase = phase_acc;
- assign wave_out = phase[31];
- endmodule
复制代码
芯片资源的使用
:
MCU部分:
- ==============================================================================
- Code (inc. data) RO Data RW Data ZI Data Debug
- 2880 142 2324 16 1632 38415 Grand Totals
- 2880 142 2324 16 1632 38415 ELF Image Totals
- 2880 142 2324 16 0 0 ROM Totals
- ==============================================================================
- Total RO Size (Code + RO Data) 5204 ( 5.08kB)
- Total RW Size (RW Data + ZI Data) 1648 ( 1.61kB)
- Total ROM Size (Code + RO Data + RW Data) 5220 ( 5.10kB)
- ==============================================================================
复制代码
FPGA部分:
实物图片
:
结语
:尝试了高云这种内置MCU的FPGA,我觉得开发起来确实是方便很多,不过硬核自带的很多外设ip给人一种不是太完善的感觉,不过想想也是,这个混合式的芯片,硬核的外设ip多半是用户定制开发的。不过还是希望官方能提供更多更优质的ip供用户选择。
附录:
`
|