guruguru123’s diary

かなり雑な作業日記です。

FPGAでArduino(7)

DDS-LSIであるad9851を駆動し、周波数・位相を高速で切り替えるためにXilinx社製のFPGA:Spaltan-6を搭載した開発用基板Papilio Proを用いて40bitのデータを書き込む。これにはZAP IDEから周波数と位相の数値データの入力し、FPGAプログラムで40bitデータを生成、ad9851をドライブする。

 

FPGAArduinoとあるが、これはFPGA上にプロセッサZPUino(Xilinx社の32bitプロセッサZPUベースのSoC)を構成し、Arduinoと同じ手順でスケッチ(Arduinoプログラム)を作成し書き込みをできるようにしたものである。ZPUinoのソースコードに回路32bit周波数データ生成回路、8bitデータ生成回路、40bit書き込み回路を追加していく。現状では、単に40bitデータの生成・書き込みが可能なプログラムができている。以下に作成したプログラムを示す。ソースコードすべてを載せると長くなってしまうので、変更部分のみ。

 

・ZPUinoトップ回路追加・変更部
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
library work;
use work.zpupkg.all;
use work.zpuinopkg.all;
use work.zpuino_config.all;
use work.zpu_config.all;
use work.pad.all;
use work.wishbonepkg.all;

entity papilio_pro_top is
~省略~
-- Papilio Note: Place your signal statements here. #Signal
signal data32: std_logic_vector(31 downto 0);
signal phasedata: std_logic_vector(7 downto 0);
signal led32:std_logic_vector(31 downto 0);
signal count_in : std_logic_vector(31 downto 0) := "00000000000000000000000000000000";
signal count_in3 : std_logic_vector(31 downto 0) := "00000000000000000000000000000000";
signal my_ad9851data : std_logic := '0';
signal count_in2 : std_logic_vector(23 downto 0) := "000000000000000000000000";
signal my_ad9851fqud : std_logic;
signal my_ad9851reset : std_logic;
signal freqcheck : std_logic_vector(31 downto 0) := "00000000000000000000000000000000";
signal phasecheck : std_logic_vector(7 downto 0) := "00000000";
signal datacheck : std_logic;
signal my_clock : std_logic;
signal x : integer range 0 to 15 := 0;
signal count_in4 : std_logic_vector(31 downto 0) := "00000000000000000000000000000000";
signal clkplus : std_logic;

component freqset is
port (
clk : in std_logic;
resetb : in std_logic;
wb_clk_i: in std_logic;
wb_rst_i: in std_logic;
wb_dat_o: out std_logic_vector(31 downto 0);
wb_dat_i: in std_logic_vector(31 downto 0);
wb_adr_i: in std_logic_vector(24 downto 0);
wb_we_i: in std_logic;
wb_cyc_i: in std_logic;
wb_stb_i: in std_logic;
wb_ack_o: out std_logic;
wb_inta_o:out std_logic;
data32:out std_logic_vector(31 downto 0)
);
end component freqset ;

component phaseset is
port (
clk : in std_logic;
resetb : in std_logic;
wb_clk_i: in std_logic;
wb_rst_i: in std_logic;
wb_dat_o: out std_logic_vector(31 downto 0);
wb_dat_i: in std_logic_vector(31 downto 0);
wb_adr_i: in std_logic_vector(24 downto 0);
wb_we_i: in std_logic;
wb_cyc_i: in std_logic;
wb_stb_i: in std_logic;
wb_ack_o: out std_logic;
wb_inta_o:out std_logic;
phasedata:out std_logic_vector(7 downto 0)
);
end component phaseset ;
~省略~
pin41: IOPAD port map(I => gpio_o(41),O => gpio_i(41),T => gpio_t(41),C => sysclk,PAD => WING_C(9) );
pin42: IOPAD port map(I => gpio_o(42),O => gpio_i(42),T => gpio_t(42),C => sysclk,PAD => WING_C(10) );
--pin43: IOPAD port map(I => gpio_o(43),O => gpio_i(43),T => gpio_t(43),C => sysclk,PAD => WING_C(11) );
--pin44: IOPAD port map(I => gpio_o(44),O => gpio_i(44),T => gpio_t(44),C => sysclk,PAD => WING_C(12) );
--pin45: IOPAD port map(I => gpio_o(45),O => gpio_i(45),T => gpio_t(45),C => sysclk,PAD => WING_C(13) );
--pin46: IOPAD port map(I => gpio_o(46),O => gpio_i(46),T => gpio_t(46),C => sysclk,PAD => WING_C(14) );
--pin47: IOPAD port map(I => gpio_o(47),O => gpio_i(47),T => gpio_t(47),C => sysclk,PAD => WING_C(15) );
//ピン43から47は後に記述するためコメントアウト
~省略~

--
-- IO SLOT 13
--

slot13: freqset
port map (
clk => sysclk,
resetb => sysrst,
data32 => data32,
wb_clk_i => wb_clk_i,
wb_rst_i => wb_rst_i,
wb_dat_o => slot_read(13),
wb_dat_i => slot_write(13),
wb_adr_i => slot_address(13),
wb_we_i => slot_we(13),
wb_cyc_i => slot_cyc(13),
wb_stb_i => slot_stb(13),
wb_ack_o => slot_ack(13),
wb_inta_o => slot_interrupt(13)
);

process (sysclk , sysrst) begin
if rising_edge (sysclk) then
if(sysrst = '1')then
count_in2 <= (23 downto 0 => '0');
else
count_in2 <= count_in2 + '1';
end if;
end if;
end process;

process (count_in2(20), sysrst) begin
if falling_edge(count_in2(20)) then
if(sysrst = '1' or count_in3(5 downto 0) = "000000"
or count_in3(5 downto 0) = "000001" or count_in3(5 downto 0) = "000010"
or count_in3(5 downto 0) = "000011" or count_in3(5 downto 0) = "000100"
or count_in3(5 downto 0) = "000101"or count_in3(5 downto 0) = "000110"
or count_in3(5 downto 0) = "110000" or count_in3(5 downto 0) = "110001"
or count_in3(5 downto 0) = "110010" )then
count_in <= (31 downto 0 => '0');
else
count_in <= count_in + '1';
end if;
end if;
end process;

process (count_in2(20), sysrst) begin
if rising_edge (count_in2(20)) then
if(sysrst = '1')then
count_in4 <= (31 downto 0 => '0');
else
count_in4 <= count_in4 + '1';
end if;
end if;
end process;

process (count_in4(0), sysrst) begin
if rising_edge (count_in4(0)) then
if(sysrst = '1' or count_in3(5 downto 0) = "110010")then
count_in3 (5 downto 0) <= "110010";--<= (31 downto 0 => '0');--
else--if(count_in(0) = '1')then
count_in3 <= count_in3 + '1';
--else
--count_in3 <= count_in3;
end if;
end if;
end process;

//ここからリセット信号と40bitデータをAD9851の各ピンに相当するレジスタへ代入
process (sysclk) begin
if rising_edge(sysclk)then
case count_in3(5 downto 0) is
when "000001" => my_ad9851reset <= '1';
when "000010" => my_ad9851reset <= '0';
when "000011" => clkplus <= '1';
when "000100" => clkplus <= '0';
when "000101" => my_ad9851fqud <= '1';
when "000110" => my_ad9851fqud <= '0';
when "000111" => my_ad9851data <= data32(31);
when "001000" => my_ad9851data <= data32(30);
when "001001" => my_ad9851data <= data32(29);
when "001010" => my_ad9851data <= data32(28);
when "001011" => my_ad9851data <= data32(27);
when "001100" => my_ad9851data <= data32(26);
when "001101" => my_ad9851data <= data32(25);
when "001110" => my_ad9851data <= data32(24);
when "001111" => my_ad9851data <= data32(23);
when "010000" => my_ad9851data <= data32(22);
when "010001" => my_ad9851data <= data32(21);
when "010010" => my_ad9851data <= data32(20);
when "010011" => my_ad9851data <= data32(21);
when "010100" => my_ad9851data <= data32(19);
when "010101" => my_ad9851data <= data32(18);
when "010110" => my_ad9851data <= data32(17);
when "010111" => my_ad9851data <= data32(16);
when "011000" => my_ad9851data <= data32(15);
when "011001" => my_ad9851data <= data32(14);
when "011010" => my_ad9851data <= data32(13);
when "011011" => my_ad9851data <= data32(12);
when "011100" => my_ad9851data <= data32(11);
when "011101" => my_ad9851data <= data32(10);
when "011110" => my_ad9851data <= data32(9);
when "011111" => my_ad9851data <= data32(8);
when "100000" => my_ad9851data <= data32(7);
when "100001" => my_ad9851data <= data32(6);
when "100010" => my_ad9851data <= data32(5);
when "100011" => my_ad9851data <= data32(4);
when "100100" => my_ad9851data <= data32(3);
when "100101" => my_ad9851data <= data32(2);
when "100110" => my_ad9851data <= data32(1);
when "100111" => my_ad9851data <= data32(0);
when "101000" => my_ad9851data <= phasedata(0);
when "101001" => my_ad9851data <= phasedata(1);
when "101010" => my_ad9851data <= phasedata(2);
when "101011" => my_ad9851data <= phasedata(3);
when "101100" => my_ad9851data <= phasedata(4);
when "101101" => my_ad9851data <= phasedata(5);
when "101110" => my_ad9851data <= phasedata(6);
when "101111" => my_ad9851data <= phasedata(7);
when "110000" => my_ad9851fqud <= '1';
when "110001" => my_ad9851fqud <= '0';
when others => my_ad9851data <= '0';
end case;
end if;
end process;

//最終的にはレジスタに蓄えていたデータを各ピンへ出力。
WING_C(12) <= my_ad9851data;
WING_C(13) <= count_in(0) or clkplus;
WING_C(14) <= my_ad9851fqud;
WING_C(15) <= my_ad9851reset;

--
-- IO SLOT 14
--

slot14: phaseset
port map (
clk => sysclk,
resetb => sysrst,
phasedata => phasedata,
wb_clk_i => wb_clk_i,
wb_rst_i => wb_rst_i,
wb_dat_o => slot_read(14),
wb_dat_i => slot_write(14),
wb_adr_i => slot_address(14),
wb_we_i => slot_we(14),
wb_cyc_i => slot_cyc(14),
wb_stb_i => slot_stb(14),
wb_ack_o => slot_ack(14),
wb_inta_o => slot_interrupt(14)
);
~省略~
end behave;
・slot13追加回路
`timescale 1ns / 1ps

module freqset(
input clk,
input resetb,
//wishboneバス信号
input wb_clk_i,
input wb_rst_i,
output [31:0] wb_dat_o,
input [31:0] wb_dat_i,
input [24:0] wb_adr_i,
input wb_we_i,
input wb_cyc_i,
input wb_stb_i,
output wb_ack_o,
output wb_inta_o,
//AD9851信号
output [31:0] data32
);

reg wb_ack_o_ff;
reg [31:0] user_data_o_ff;
reg [31:0] user_data_i_ff;
reg [31:0] data_o;
reg [31:0] freqbit;
reg [31:0] freqdata=0;
reg [31:0] freqif;
reg outdata;
reg check;
integer i,j,k;

assign wb_ack_o = wb_ack_o_ff;
assign wb_inta_o = 1'b0;
assign wb_dat_o = data_o;

always @(posedge wb_clk_i)
begin
if(wb_cyc_i == 1'b1 && wb_stb_i == 1'b1 && wb_ack_o == 1'b0)
wb_ack_o_ff <= 1'b1;
else
wb_ack_o_ff <= 1'b0;
end

always begin
begin
case(wb_adr_i[5:2])
4'b0000:data_o = freqbit;
4'b0001:data_o = user_data_i_ff;
default:data_o = 1'b0;
endcase
end
end

always @(posedge wb_clk_i)
begin
if(wb_cyc_i == 1'b1 && wb_stb_i == 1'b1 && wb_we_i == 1'b1)
case(wb_adr_i[5:2])
4'b0000:user_data_o_ff = wb_dat_i;
default:user_data_o_ff = user_data_o_ff;
endcase
end

//32bitデータ生成
always @(posedge wb_clk_i)
begin:label1
freqdata = user_data_o_ff;
for(i=31; i>=0; i=i-1)begin
freqif = freqdata%2;
freqdata = freqdata/2;
if(freqif == 32'd1)
freqbit[i] = 1'b1;
else if(freqif == 32'd0)
freqbit[i] = 1'b0;
else
freqbit[i] = 1'b0;
end
end

assign data32 = freqbit;

endmodule

・slot14追加回路
`timescale 1ns / 1ps

module phaseset(
input clk,
input resetb,
//wishboneバス信号
input wb_clk_i,
input wb_rst_i,
output [31:0] wb_dat_o,
input [31:0] wb_dat_i,
input [24:0] wb_adr_i,
input wb_we_i,
input wb_cyc_i,
input wb_stb_i,
output wb_ack_o,
output wb_inta_o,
//ad9851信号
output [7:0] phasedata
);

reg wb_ack_o_ff;
reg [31:0]user_data_o_ff;
reg [31:0]user_data_i_ff;
reg [31:0]data_o;
reg [7:0] my_phasedata;
reg [31:0]phaseif;
reg [32:0]datacheck;
integer i,j,k;

assign wb_ack_o = wb_ack_o_ff;
assign wb_inta_o = 1'b0;
assign wb_dat_o = data_o;

always @(posedge wb_clk_i)
begin
if(wb_cyc_i == 1'b1 && wb_stb_i == 1'b1 && wb_ack_o == 1'b0)
wb_ack_o_ff <= 1'b1;
else
wb_ack_o_ff <= 1'b0;
end

always begin
begin
case(wb_adr_i[5:2])
4'b0000:data_o = my_phasedata;
4'b0001:data_o = user_data_i_ff;
default:data_o = 1'b0;
endcase
end
end

always @(posedge wb_clk_i)
begin
if(wb_cyc_i == 1'b1 && wb_stb_i == 1'b1 && wb_we_i == 1'b1)
case(wb_adr_i[5:2])
4'b0000:user_data_o_ff = wb_dat_i;
default:user_data_o_ff = user_data_o_ff;
endcase
end

//8bitデータ生成
always @(posedge wb_clk_i)
begin:label1
datacheck = user_data_o_ff;
my_phasedata[0]=1'b1;
my_phasedata[1]=1'b0;
my_phasedata[2]=1'b0;
for(i=3; i<8; i=i+1)begin
phaseif = datacheck%2;
datacheck = datacheck/2;
if(phaseif == 32'd1)
my_phasedata[i] = 1'b1;
else if(phaseif == 32'd0)
my_phasedata[i] = 1'b0;
else
my_phasedata[i] = 1'b0;
end
end

assign phasedata = my_phasedata;

endmodule

A5-3 ZAP IDE作成プログラム
ソフトウェアArduinoにおけるAD9851の駆動の際に作成したスケッチを以下に示す。
//スロット13のアドレス定義
#define UREGBase IO_SLOT(13)
#define UREG_OUT REGISTER(UREGBase,0);
#define UREG_IN REGISTER(UREGBase,1);

//スロット14のアドレス定義
#define UREGBase2 IO_SLOT(14)
#define UREG_OUT2 REGISTER(UREGBase2,0);
#define UREG_IN2 REGISTER(UREGBase2,1);

void setup(){
Serial.begin(9600);
}

void loop(){
int data;
int data2;
int freqdata;
int outputfreq;
int outputphase;
int x;
int y;

 //レジスタ用ポインタ
volatile unsigned int *ureg_out = &UREG_OUT;
volatile unsigned int *ureg_in = &UREG_IN;

volatile unsigned int *ureg_out2 = &UREG_OUT2;
volatile unsigned int *ureg_in2 = &UREG_IN2;

data=1;
data2=1;
//出力周波数、位相を入力
outputfreq=10000000;
outputphase=0;

while(1){
x=180000000/outputfreq;
freqdata=4294967295/x;
y = outputphase/11.25;
*ureg_out = freqdata;
*ureg_out2 = y;

data=*ureg_in;
data2=*ureg_in2;
Serial.println(data,BIN);
delay(100);
}
}