https://insoobaik.tistory.com/648
이전에 SPI를 ILA를 통해 전달되는 신호를 확인하고 Synthesis부터 Post Layout Simulation을 통해 코드가 정상적으로 실행되는 것을 확인하였다.
https://insoobaik.tistory.com/630
위에서 SPI 통신을 통해 전달 받은 Data를 이전에 실습해본 Dc Motor를 제어해 볼 것이다.
위 그림은 SPI와 DC_Motor 모듈이 각각의 Top 모듈 안에서의 상호작용을 나타낸 것이다.
아두이노(SPI_Master)를 통해 spi_slave에게 Data를 전달하면 Data 중 마지막 4bit를 Duty Cycle로 사용하게 된다.
Duty Cycle은 4bit를 16등분 하여 전달되는 Data 따라 정해진다.
(예를 들어 1111이 들어오면 16중에 16이 1이기 때문에 Duty Cycle은 100%가 되고, 1000이 들어오게 되면 16중에 8이 1이기 때문에 Duty Cycle은 50%가 된다.
*추가로 평균 전압은 DC_Moter를 동작 시키기 위한 최소 전압 이상이 되어야 한다.)
Output Pin의 pwm_out이 Duty Cycle을 정하게 된다. (nsleep의 경우 Data Sheet를 보게되면 1을 전달해야 DC Motor가 동작하게 되어있다.)
Schematic
spi_slave
motor
f값 전달
아두이노를 통해 f(1111) 신호를 전달하게 마지막 4비트에 1111이 전달되고, 1111이 전달되면 Duty Cycle이 100%가 되기 때문에 위와 같이 PWM이 1의 신호를 계속해서 유지하는 것을 확인할 수 있다.
8값 전달
아두이노를 통해 f(1000) 신호를 전달하게 마지막 4비트에 1000이 전달되고, 1000이 전달되면 Duty Cycle이 50%가 되기 때문에 위와 같이 PWM이 1의 신호를 계속해서 유지하는 것을 확인할 수 있다.
실행 영상
전체 코드
spi_slave.v
`define ESTA_READY 2'b00
`define ESTA_READ 2'b01
`define ESTA_WRITE 2'b10
module spi_slave(sclk, cs, id, mosi, miso, reset, duty);
input sclk, cs, mosi, reset;
input [1:0] id;
output reg miso;
output [3:0] duty;
//received_data
reg [31:0] received_data;
//bitcnt
reg [5:0] bitcnt;
always @(negedge sclk or posedge cs) begin
if(cs) begin
received_data[31:0] <= 0;
end
else begin
if(bitcnt < 33) begin
received_data[31:0] <= {received_data[30:0], mosi};
end
else begin
received_data[31:0]<= received_data[31:0];
end
end
end
always @(negedge sclk or posedge cs) begin
if (cs) begin
bitcnt <= 0;
end
else begin
if(bitcnt < 33) begin
bitcnt <= bitcnt + 1;
end
else begin
bitcnt <= 0;
end
end
end
//id_check
reg id_check;
always @(posedge sclk or posedge cs) begin
if(cs) begin
id_check <= 0;
end
else begin
if(bitcnt == 2 && id[1:0] == received_data[1:0])
id_check <= 1;
else if(bitcnt == 2 && id[1:0] != received_data[1:0])
id_check <= 0;
else
// ? ? ?
id_check <= id_check;
end
end
//current_state
reg [1:0] current_state;
//next_state
reg [1:0] next_state;
always @(negedge sclk or posedge cs) begin
if(cs) begin
current_state <= 0;
end
else
current_state <= next_state;
end
always @(posedge sclk or posedge cs) begin
if(cs) begin
next_state <= 0;
end
else begin
case(current_state)
`ESTA_READY : begin
if(bitcnt == 3 && received_data[0] == 1'b1 && id_check == 1)
next_state <= `ESTA_READ;
else if(bitcnt == 3 && received_data[0] == 1'b0 && id_check == 1)
next_state <= `ESTA_WRITE;
else
next_state <= next_state;
end
`ESTA_READ : begin
if(bitcnt == 0)
next_state <= `ESTA_READY;
else
next_state <= next_state;
end
`ESTA_WRITE : begin
if(bitcnt == 0)
next_state <= `ESTA_READY;
else
next_state <= next_state;
end
endcase
end
end
//address
reg [1:0] address;
always @(posedge sclk or posedge cs) begin
if(cs) begin
address <= 0;
end
else begin
if(bitcnt == 4 && received_data[0] == 0) begin
address <= 2'b01;
end
else if(bitcnt == 4 && received_data[0] == 1) begin
address <= 2'b10;
end
else
address <= address;
end
end
//register D0, D1
reg [15:0] REG_D0;
reg [15:0] REG_D1;
always @(posedge sclk or posedge reset) begin
if(reset) begin
REG_D0[15:0] <= 0;
end
else begin
if(current_state == `ESTA_WRITE && address == 2'b01 && bitcnt == 32)
REG_D0[15:0] <= received_data[15:0];
else begin
REG_D0[15:0] <= REG_D0[15:0];
end
end
end
always @(posedge sclk or posedge reset) begin
if(reset) begin
REG_D1[15:0] <= 0;
end
else begin
if(current_state == `ESTA_WRITE && address == 2'b10 && bitcnt ==32)
REG_D1[15:0] <= received_data[15:0];
else begin
REG_D1[15:0] <= REG_D1[15:0];
end
end
end
//miso
always @(posedge sclk or posedge cs) begin
if(cs)
miso <= 0;
else if(current_state == `ESTA_READ && address == 2'b01) begin
case(bitcnt)
5'd16 : miso <= REG_D0[15];
5'd17 : miso <= REG_D0[14];
5'd18 : miso <= REG_D0[13];
5'd19 : miso <= REG_D0[12];
5'd20 : miso <= REG_D0[11];
5'd21 : miso <= REG_D0[10];
5'd22 : miso <= REG_D0[9];
5'd23 : miso <= REG_D0[8];
5'd24 : miso <= REG_D0[7];
5'd25 : miso <= REG_D0[6];
5'd26 : miso <= REG_D0[5];
5'd27 : miso <= REG_D0[4];
5'd28 : miso <= REG_D0[3];
5'd29 : miso <= REG_D0[2];
5'd30 : miso <= REG_D0[1];
5'd31 : miso <= REG_D0[0];
default : miso <= 0;
endcase
end
else if(current_state == `ESTA_READ && address == 2'b10)begin
case(bitcnt)
5'd16 : miso <= REG_D1[15];
5'd17 : miso <= REG_D1[14];
5'd18 : miso <= REG_D1[13];
5'd19 : miso <= REG_D1[12];
5'd20 : miso <= REG_D1[11];
5'd21 : miso <= REG_D1[10];
5'd22 : miso <= REG_D1[9];
5'd23 : miso <= REG_D1[8];
5'd24 : miso <= REG_D1[7];
5'd25 : miso <= REG_D1[6];
5'd26 : miso <= REG_D1[5];
5'd27 : miso <= REG_D1[4];
5'd28 : miso <= REG_D1[3];
5'd29 : miso <= REG_D1[2];
5'd30 : miso <= REG_D1[1];
5'd31 : miso <= REG_D1[0];
default : miso <= 0;
endcase
end
else
miso <= 0;
end
assign duty[3:0] = REG_D0[3:0];
//ila
// ila_0 U0(
// .clk(clk),
// .probe0(cs),
// .probe1(sclk),
// .probe2(mosi),
// .probe3(miso),
// .probe4(bitcnt),
// .probe5(address),
// .probe6(current_state),
// .probe7(REG_D0)
// );
endmodule
motor.v
module motor(
input [3:0] duty,
input clk,
input reset,
output reg pwm_out,
output wire nsleep
);
reg [25:0] counter;
reg [3:0] pwm_counter;
assign nsleep = 1;
always @(posedge clk or posedge reset) begin
if(reset) begin
pwm_out <= 0;
counter <= 0;
pwm_counter <= 0;
end
else begin
if(counter >= 49999) begin
counter <= 0;
pwm_counter <= pwm_counter +1;
if(pwm_counter >= 15) begin
pwm_counter <= 0;
end
end
else begin
counter <= counter+1;
end
if(pwm_counter < duty)
pwm_out <= 1;
else
pwm_out <= 0;
end
end
endmodule
'Semiconductor > FPGA' 카테고리의 다른 글
FPGA - IP 생성 및 Vitis를 이용한 Switch, LED 제어 (0) | 2024.09.19 |
---|---|
FPGA - STM32 UART 이용한 DC Motor 제어 및 신호 확인 (0) | 2024.07.30 |
FPGA - CHARACTER LCD에 문자 입력하기 (0) | 2024.06.18 |
FPGA - FPGA를 이용한 DC 모터 구동 (0) | 2024.06.11 |
FPGA - 7-Segment Count Up (0~9999) / FPGA (0) | 2024.06.02 |