10월 7일
c언어로 펌웨어 구조 만드는 법.
c언어가 크기가 작으면서 속도가 빨라서 대부분 c언어로 펌웨어를 만든다고 함. c++보다도 작으면서 빠름.
구조체와 포인터 활용이 중요함.
-----
어제 했던 구조 비슷하게 다시 코딩.
module digit_select_decoder(
input [1:0] i_digit_position,
input i_En,
output [3:0] o_select_position
);
reg [3:0] r_select_position;
assign o_select_position = r_select_position;
always @(i_digit_position or i_En) begin
if (i_En) begin
r_select_position = 4'b1111;
end
else begin
case (i_digit_position)
2'b00 : r_select_position = 4'b1110;
2'b01 : r_select_position = 4'b1101;
2'b10 : r_select_position = 4'b1011;
2'b11 : r_select_position = 4'b0111;
endcase
end
end
endmodule
module BCDtoFND_decoder(
input [3:0] i_a,
input i_En,
output [7:0] o_font
);
reg [7:0] r_font;
assign o_font = r_font;
always @(i_En or i_a) begin
if(i_En) begin
r_font = 8'hff;
end
else begin
r_font = 8'hff;
case (i_a)
4'h0 : r_font = 8'hc0;
4'h1 : r_font = 8'hf9;
4'h2 : r_font = 8'ha4;
4'h3 : r_font = 8'hb0;
4'h4 : r_font = 8'h99;
4'h5 : r_font = 8'h92;
4'h6 : r_font = 8'h82;
4'h7 : r_font = 8'hf8;
4'h8 : r_font = 8'h80;
4'h9 : r_font = 8'h90;
4'ha : r_font = 8'h7f;
endcase
end
end
endmodule
module BCDtoFND(
input [1:0] i_digit_position,
input i_En,
input [3:0] i_value,
output [3:0] o_select_position,
output [7:0] o_font
);
digit_select_decoder udt1(
.i_digit_position(i_digit_position),
.i_En(i_En),
.o_select_position(o_select_position)
);
BCDtoFND_decoder udt2(
.i_a(i_value),
.i_En(i_En),
.o_font(o_font)
);
endmodule
어제 contraints는 switch와 FND 부분을 수정해서 사용했다. 만약 다른 칩과 연동하고 싶으면 switch가 아니라 pmode 부분을 수정해서 입력을 받으면 된다.
JA에 다음과 같이 할당하여 사용해보겠다.
4 3 2 1 : value
10 9 8 7
10은 i_En, 8 7은 digit position.
다른 칩으로 이전 수업에서 사용해서 구석에 남아있는 stm32f411re 칩을 사용하겠다. 그래서 다시 한 번 STM32 Cube IDE 1.10.1 버전을 켰다.
system core의 RCC 항목에서 HSE, LSE는 다음과 같이 설정했다.
--------
//외부인터럽트는 8MHz ??
수업 중간에 잠깐 지나가면서 말씀하신 거라 제대로 못 들은 거일 수도 있는데 외부 인터럽트의 최대 주파수라고 말씀하셨다. 그래서 stm32 외부 인터럽트를 키워드로 검색해보니까 이런 내용이 나왔다.
" 외부클럭소스(External Clock Source)의 동기화

D플립플롭 회로로 동기화된 클럭의 출력되는 클럭 Q는 다음과 같습니다.(아래 그림과 같이 외부입력되는 클럭이 타이머에 제공될때는 지연 시간을 최대 버스클럭의 3 클럭까지 갖을 수 있습니다. 그러므로 동기화를 하는 외부클럭소스(External Clock source)의 주파수의 3배수는 APBx 클럭의 주파수를 넘어설 수 없습니다.)
-
f(TIMCLK)는 버스클럭(APB Bus Clock)과 외부클럭과의 동기화에 의해 출력된 클럭입니다.
-
f(External Clock)은 패드에 입력되는 클럭이 아닌 동기화 블럭에 입력되는 클럭입니다. TIMx_ETR에 입력되는 클럭은 프리스케일(Prescale) 블럭이 있어 버스클럭을 3분주 클럭보다 큰 클럭 입력은 가능하나 프리스케일(Prescale) 후의 클럭은 버스클럭의 3분주보다 작아야 합니다. "
출처
https://m.blog.naver.com/duvallee/221459826325
[06] STM32 Timer
1. 타이머(Timer) 타이머(Timer)는 주기적으로 시간을 얻을 때 사용하는 디지털 카운터 회로입니다. 보통...
blog.naver.com
이것과 비슷한 메커니즘으로 외부 인터럽트 주파수의 제한이 있는 거 같다. 데이터시트를 읽음이 백 번 타당하나 내부 외부 클럭 주파수에 대한 한계치가 있고 그게 다르다 정도만 알고 넘어가도록 하겠다. 전부 이해하기엔 능력과 시간이 부족하다...
-------
시스템 코어에서 설정한 뒤 Clock configuration으로 넘어갔다.
HSE냐 HSi를 선택하는 MUX가 있음
PLL 선택 후 100MHz입력(최대값임)
위에서 설정한 pmod를 다시 가져오면
"4 3 2 1 : value
10 9 8 7
10은 i_En, 8 7은 digit position."
각각에 대한 stm32 pin 할당은 다음과 같다.
value [0:3] PC10, PC12, PC11, PD2
digit_position PA2, PA3
enable PC4
전부 GPIO output으로 설정함
오랜만에 하는 거라서 연습코드를 간단하게 작성했다.
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(200);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
제대로 작동했다.
Button이라는 사용자 정의 자료형을 이용한다.
Button ledButton; --> 선언과 함께 stack 메모리 영역에 TypeDef*, uint16_t, int만큼 선언.
firmware는 메모리가 작아서 stack 영역에서도 많이 씀.
기본 선언형을 보면 구조체에 대한 포인터변수와 uint16_t 변수를 받는 걸 알 수 있다.
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
선언한 Button자료형에 값을 대입하는 게 Button_GetInstance 함수.
void Button_GetInstance(Button *btn, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
클래스가 없기 때문에 클래스처럼 Button_을 앞에 이름 붙인 거임.
변수 이름을 직관적으로 선언가능하고 인스턴스만 받으면 되기 때문에 새로운 버튼 선언할 때 getState1,2,3,...으로 만들지 않아도 됨.
--------
C++과 C언어는 이름 생성하는 게 조금 다름.
(관용적으로 camel case로 쓸 때 이렇다는 거.)
C : 함수 첫 번째 글자 대문자 underbar 이후에도 첫 번째 글자 대문자. ex) Button_Ge ...
C++ : 함수 첫 번째 글자 소문자. ex) Button(클래스) ge...
이것도 의식적으로 맞춰줘야 하나 조금 의문이긴 함. snake case가 더 취향이라서..
---------
TIM 1
100MHz
1/주기로 시간 계산은 여러 번 했으니 헷갈리지 말자.
코드 전문은 github으로 대체한다.
https://github.com/316415/MCUtoFPGA.git
GitHub - 316415/MCUtoFPGA: By using pmod, STM32F411RE transfers data to basys3. it's timer counter that counts every 0.1 seconds
By using pmod, STM32F411RE transfers data to basys3. it's timer counter that counts every 0.1 seconds. - GitHub - 316415/MCUtoFPGA: By using pmod, STM32F411RE transfers data to basys3. it's...
github.com
이번에 코딩할 때는 객체지향 비슷하게 구조 짜는 법을 알려주셨다.
int Button_GetState(Button *btn)
클래스를 통한 상속이 없기에 함수 선언 시 Button_이나 Led_와 같이 이름 앞에 덧붙여서 알렸다.
//새로 Button_GetState 함수를 만들 때 차이나는 인수는 global로 선언된 prevState1,2,3...과 읽어들이는 PIN 번호이다.
//틀린 것만 묶는다. How? --> structure!
typedef struct _button{
GPIO_TypeDef* GPIOX;
uint16_t GPIO_Pin;
int prevState;
}Button;
//int prevState = 0; 이제 global 변수는 필요없다.
기존에 배웠던 방식에선 사용하는 버튼이 늘어남에 따라 getState1, getState2 ... 등과 같이 함수가 늘어났다.
버튼 작동에 대한 함수는 동일하게 하나로 가져가고 버튼이 늘어날 때 달라지는 요소만 구조체로 선언하고 구조체로 필요인수를 받아들여서 함수를 선언함으로써 버튼에 대한 동작 함수는 늘어나지 않는다.
동작은 그냥 FND에서 타이머가 쭉 출력되는 거 말고는 없다.
https://youtube.com/shorts/kffWw9kM_zQ?feature=share

과제
이전 C++로 만들었던 UML Object Diagram을 적용해서, FSM을 구현해라.
10월 8일
과제 완료해서 추가. 근데 FSM에서 reset에서 다시 stop으로 돌아가는 단계가 이해가 안 됨. 그래서 그냥 reset 버튼 누르면 0으로 초기화하고 대기하는 걸로만 적용.
https://github.com/316415/MCUtoFPGA_TimerButton.git
GitHub - 316415/MCUtoFPGA_TimerButton: It's timer counter that counts every 0.1 seconds and has 2 buttons, run and reset. when y
It's timer counter that counts every 0.1 seconds and has 2 buttons, run and reset. when you want to start or stop the timer, push the run button. If you want to reset the time, push the reset b...
github.com
https://github.com/316415/MCUtoFPGA_TimerButton_FPGA.git
GitHub - 316415/MCUtoFPGA_TimerButton_FPGA
Contribute to 316415/MCUtoFPGA_TimerButton_FPGA development by creating an account on GitHub.
github.com
https://youtube.com/shorts/9p8zt0IHmjQ?feature=share
