Kraklog

상태천이를 통한 PWM 컨트롤 본문

Study/FPGA

상태천이를 통한 PWM 컨트롤

Krakens 2023. 12. 10. 02:20
728x90

개발보드 : DE1-SOC

사용툴 : Quarturs Prime lite edition , Eclipse for nios 

 

module PWMCtrl (
  input           clk    ,
  input           rst	 ,
  output		  led
  );
  
   reg [15:0] counter0;
   
   always @(negedge rst | posedege clk)
   begin
   counter0 <=0;
   end else begin
   counter0 < counter0 +1;
   end
   end
   
   
  ...

클럭을 발생시켜주고, 최상위 비트에 LED를 연결해주는 코드를 작성하고, 보드의 핀맵을 찾아 연결해주었다.

 

 

이때 보드는 LED가 깜빡이게 되는데, 50Mhz 를 2^16 으로 분주하여 LED0의 16번째에 할당해주고,  65,536 * (1/50Mhz)  sec 동안 깜빡이게 된다. 

만약 LED의 점멸을 on / off 의 비율이 1:1로 동작하게 하고 싶다면 초기화 조건을해주면 되는데 

  wire counter0_clr;
    wire counter0_dec;
    reg [16:0]  counter0 ;

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            counter0 <=1'b0;
        end else begin
            if(counter0_clr) begin
                counter0 <= 1'b0;
            end else begin
                counter0 <= counter0 +1'b1;     
            end
        end
    end

 

wire를 선언해주고, 초기화 조건을 걸어준다.

 

 assign  counter0_clr = (counter0 >= 49999999) ? 1'b1 : 1'b0;

그 후 wire에 할당을 해주는데, 50Mhz로 동작ㄱ학고 있기 때문에 50Mhz 에 clr값이 들어가게 삼항연산자를 이용해준다.

-counter0 >= 49999999 일때 1'b1을 그렇지 않으면 1'b0을 넣어주는 조건문

 

1Hz 점멸, 50% duty 동작

 

Platform design을 통해 마이크로 컨트롤러 시스템을 구축해준다.
CPU와 메모리 설정, PIO를 연결해 동작환경을 구축해주고 Generate를 해준 후 보드에 다시 올려준다.

Eclipse에서 hello world small 템플릿을 통해서 C언어 기반의 소스를 다시 짜주었다.

PERIODE와 DECODE 베이스 주소에 값을 설정하여 정확한 동작을 해주도록 하기 위함이다.

int main()
{
while(1){
*(volatile unsigned long *) Period0_base = 50000000;
*(volatile unsigned long *) Period0_base = 25000000;
}


}

대략적인 골자는 다음과 같다.

주소를 확인하고, 제대로 연결을했다면, 위 GIF처럼 동작을 하게 된다.

 

다음으론 7-segment 와 Push 스위치의 주소를 할당해주고, 파이프라인을 연결해 Generate를 했다. 

쿼터스에 핀을 연결할 때 show 기능을 사용하면 좀 더 편하게 연결해줄 수 있다.

 

이제, 7-segment 와 Push 버튼을 보드의 핀맵을 참조해서 연결해줘야하는데 

핀 플래너를 통해 하나하나 연결하는 방법도 있지만,

set_location_assignment  를 이용해서 할당해주는 방법도 있다.

".qsf" 파일을 통해 편집,&nbsp;https://www.macnica.co.jp/en/business/semiconductor/articles/intel/209/

Synthesis를 해주고 핀 플래너에 들어가면, 처음과 마찬가지로 연결되어있다.

7-segment는 연결만 해놨기 때문에 8이 들어오고, 1Hz LED 점멸이 들어오는 동작을 확인 할 수 있다.

 

	void SetPeriod(int n){
		if(n==0) 	  Period0 = 50000000;
		else if(n==1) Period0 = 40000000;
		else if(n==2) Period0 = 35000000;
		else if(n==3) Period0 = 30000000;
		else if(n==4) Period0 = 25000000;
		else if(n==5) Period0 = 20000000;
		else if(n==6) Period0 = 16000000;
		else if(n==7) Period0 = 13000000;
		else if(n==8) Period0 = 10000000;
		else if(n==9) Period0 = 8000000;
		else if(n==10)Period0 = 6000000;
		else if(n==11)Period0 = 5000000;
		else if(n==12)Period0 = 4000000;
		else if(n==13)Period0 = 3500000;
		else if(n==14)Period0 = 3000000;
		else if(n==15)Period0 = 2500000;

		Decode0 = Period0 >> 1;
		*(volatile unsigned long *) PERIOD0_BASE = Period0;
		*(volatile unsigned long *) DECODE0_BASE = Decode0;

	}


int main()
	{
		unsigned long reg1 =0;
		unsigned long reg1old,reg1tmp,reg2tmp,reg3tmp;

		*(volatile unsigned long *)PERIOD0_BASE =Period0;
		*(volatile unsigned long *)DECODE0_BASE =Decode0;
		*(volatile unsigned long *)HEX0_BASE =0xc0;
	while(1){
		reg1old = reg1;
		reg1tmp = *(volatile unsigned long *)PUSH_BASE;
		_wait(10000);
		reg2tmp = *(volatile unsigned long *)PUSH_BASE;
		_wait(10000);
		reg3tmp = *(volatile unsigned long *)PUSH_BASE;
		_wait(10000);
		reg1 = *(volatile unsigned long *)PUSH_BASE;
		if(reg1 == reg1tmp && reg1 == reg2tmp && reg1 == reg3tmp)reg1=reg1;
		else reg1 = reg1old;

		if(reg1 != reg1old){
			_wait(200000);
		}

		if((reg1 & 0x03)==0x01){
			if(buttoncount ==15)buttoncount=0;
			else buttoncount++;
		}
		if((reg1 & 0x03)==0x02){
			if(buttoncount == 0)buttoncount=15;
			else buttoncount--;
	}
		*(volatile unsigned long *)HEX0_BASE=SevenSegEnc(buttoncount);
		SetPeriod(buttoncount);
	}
	return 0;
	}

버튼의 입력값에 따른 주기를 변화시켜주는 코드를 업로드 해주면 버튼에 따른 PWM을 조절 할 수 있다.

이제 처음 목표였던 8개의 PWM을 조절하기 위해서 PERIOD 0~7 , DECODE 0~7을 연결해주었다.

        always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            counter2 <=1'b0;
        end else begin
            if(counter2_clr) begin
                counter2 <= 1'b0;
            end else begin
                counter2 <= counter2 +1'b1;     
            end
        end
    end

    assign  counter2_clr = (counter2 >= period2-1) ? 1'b1 : 1'b0;
    assign  counter2_dec = (counter2 <  decode2-1) ? 1'b1 : 1'b0;
    assign LEDR[2] = counter2_dec;

 

 

7-segment를 다루기 위해서 (4개) PIO를 추가해주었다.
reset을 연결해주고, slave를 data master 연결해주고, clk을 동기화해주면 에러가 사라진다.
모든 연결을 해주고, 에러가 없다면 generate를 해주고 Qsys에서 인풋값과 아웃풋 값을 잡아준뒤 핀맵을 할당해준다.

 

모두 이상이 없다면 보드에 올려준다.

 

 

정상적으로 보드에 올려준다면 Segment 4개와 LED 7개가 들어온다.

 

이제 Eclipse를 통해 빌드를 해주겠다.

 

-마이크로 컨트롤러를 이용한 복잡한 상태천이는 스테이트 머신을 통해 다룰 수 있는데, 복잡해진다는 문제가 있다. 

또한 마이크로 컨트롤러는 병렬 동작이 힘들다는 단점을 갖고 있는데, 병렬 동작을 갖고 있지만 않다면 다루기 좋다는 장점을 갖고 있다.

 

따라서 Nios + C를 통해서 4개의 세그먼트와 스위치 3개 (리셋, 입력, 설정) 를 통해 값을 입력시킬것인데 

HEX3 은 LED의 위치를, HEX2는 F(frequency), D(duty)를 , HEX1~0 은 설정 값을 표현하게 해줄 예정.

 

sate machine을 이용해서 각 상태에 맞는 값을 입력해준다.

 

 

 

Board : DE1-SOC

Tool : Quartus

Key0 : Reset   /  Key1 : Select   /  Key2 : Setting

HEX3 : LED Position   /   HEX2 : F= Frequency, D=Duty  /  HEX1~0 : Value

 

영상에서 동작을 설명하면

LED 위치 Frequncy / Duty Value Value

각각 이렇게 의미하고 있다.
키 입력을 하면 BCD가 깜빡이게 되는데, 이때 값들을 입력이 가능하다.
F는 frequency 로 01 02 05 .. 1h 이런식으로 벼화하는데 1h는 hundred로 최대 500Khz까지 PWM을 입력할 수 있다.
D는 Duty로 10% 20%... 90% 까지 조절이 가능하다.

 

 

이제 이 파일들을 Rom에 올려서 부팅때마다 De1-Soc default sof파일이 아닌 개발하고 있는 내용이 돌아가게끔 하려는데 ...

DE1-SoC_User_manual.pdf
6.33MB
DE1-SoC_FAQ_en.pdf
0.33MB

 

내용에 맞춰 ROM에 올렸으나.. Nios 의 SW는 올라가지 않는 문제점이 발생.

EPCS128에 올리는 방식이 문제가 되는듯하지만.. 해결방안을 현재로써는 찾기가 어려워 찾게되면 진행하도록 한다.

728x90

'Study > FPGA' 카테고리의 다른 글

VideoProc  (0) 2023.12.20