[IDEC] ARM Cortex-M 프로세서 기반의 펌웨어 설계실무 3

2023. 8. 10. 16:20Embedded/ARM Cortex

728x90

3일차

리셋이 되면 최초실행되는 명령어가 vectors 테이블의 0번지 - 0번지는 bin파일내용

 

mcu내부에 sram – sram 시작 주소 : 2천만번지

스택은 램에있어야한다. – push, pop하기 위해

스택 사이즈 -

4001024바이트 정도이다.

Stack_mem

 

 

ARM 프로세서

 

ARM에선 스택의 증가방향 주소가 감소

SP가 스택의 푸쉬를 하면할수록 내려간다(1024바이트의 위에서 중간으로) / 팝하면 다시 증가함

PUSHPOP명령어가 있는데 PUSH{ }POP{ }  { }는 레지스터만 들어갈 수 있다.

 

PUSH{R0 – R3} <-

POP {R0 – R3} ->

 

스택의 용도 : 전역변수는 빌드하면 주소 고정

지역변수는 빌드하면 주소가 유동적 스택에 사용됨

 

Main에 오기전에 실행되는 과정

-      전원을 껐다켜면 램의 값은 전부 쓰레기값이 된다.

-      Main에 와서 해당 영역의 값을 읽어보면 5로 출력(print”%d”부분에)

- bin파일(rom에 들어갈)에 초기 값들이 들어가 있다.(rom에 존재)

           - section초기화 작업

           - 스택의 값이 최초에선 rom에 존재하고, 실행하면 ram에 복사되어 온다.

           - 빌드를 하면 여러곳에 흩어진 전역변수들이 모이게 된다. (인접한 주소를 가지게 된다.)

           - 0으로 만들어지는 변수들도 sram에서 따로 모으고, 0이아닌 값으로 만들어지는 변수들도 따로 모은다.

 

Int gvar = 5;

Void main (){

           Printf(“%d”,gvar);

           Gvar = 0;

}

 

 

SFR = SFR ^ (0x1<<6);

프리스마크(스택의 우선순위가 프리마스크의 값이 된다.)

LOAD, OPERATION. STORE

 

 

 

BASEPRI – 레벨 마스킹 만약 5를 쓴다면 우선순위가 5가 된다. 집어넣은 값만큼 우선순위가 정해진다. 시스템의 우선순위가 그값 만큼 된다.

1~255까지가 해당 값

 

우선순위 – IRQ에 의해서만 이루어진다.

 

인터럽트가 안되고 delay에 있는 것을 확인할 수 있다.


 

초기 해줘야 할 설정

1.     클럭 설정

2.     디버거 설정

디버거 설정을 먼저해줘야 다운로드 받을 수 있다.

 

디버거 설정

위의 5개 핀이 실제 보드의 JTAG쪽과 연결되어 있다 보면 된다.

외부 크리스탈 우리가 사용하는 보드의

CPU 외부
CPU 내부
내부 주파수 설정 : 우리가 사용하는 보드는 72MHz까지 사용가능하므로 72로 설정

UART가 동작하기 위한 필수 설정이 빠져있으면 노란색으로 표시

UART1, Asynchronous, baud rate : 115200으로 설정한다.

 

Hal로 시작되는 것과 hal로 시작되지 않는 것이 있는데 hal이 없는 것은 사용하면 x

Halstatic으로 정의되어있는데 static붙어있는 함수는 외부로 호출할 수 없음

uint8_t c;
		HAL_StatusTypeDef STATUS = HAL_UART_Receive(&huart1, &c, sizeof(c), 100);
		if(STATUS == HAL_OK)
		{
			HAL_UART_Transmit(&huart1, &c, sizeof(c), (uint32_t)-1 );
		}
		
		HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5 | GPIO_PIN_6);

HAL_StatusTypeDef STATUS = HAL_UART_Receive(&huart1, &c, sizeof(c), 100);

해당 코드는 HAL_UART_Receive함수의 변환값인 HAL_StatusTypeDef status에 넣어 실행한다.

UART1 -> NVIC -> USART1 global interrupt check 하면 uart 인터럽트 사용 가능

Hal 드라이버의 구조 문제로 인터럽트 한번 실행하면 다음은 disable이 되어버린다.

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
	
	if(huart == &huart1){
		HAL_UART_Receive_IT(&huart1, &uart_rx_data, sizeof(uart_rx_data));
		HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5 | GPIO_PIN_6);
	}
	
}

인터럽트로 led 점등 – uart로 입력받음

 

 

 

  • DMA

ADD USART1_RX - Circular선택한다.

테라텀에 입력하면 메모리가 할당되는 것을 볼 수 있다.

2바이트 먼저 전송 하면서, 나머지 2바이트는 데이터 입력을 받는다.

4 천만 : sfp의 주소
배열의 주소 : 2천만

위 아래 둘다 같은 기능을 한다.

 

Stm32내부에 adc ip가 존재한다.

DMA스타트 후 ADC컨버터 하면 종료되는데, ENABLE시켜두면 계속 ADC를 사용 가능하게 한다.

한 클럭당 한 비트가 나온다 (ADC변환 시)

변환된 레지스터의 값이 DR에 저장될 것이다..

어두울 때 /  밝을 때

 

 

 

파일 입출력을 사용하기 위해 stdio.h을 추가한다.

 

 

Adc를 스타트 시키고 adc의 값을 adc_value에 저장한 후, 그 값을 숫자로 출력시킨다.

 

 

밝을 때 출력  / 밑의 어두울 때 출력

 

필터 알고리즘 : adc값의 편차가 클 때 사용하면 좋다

P(n) : 예측값/ 사용자에게 보여주는 값

 

while (1)
  {
		uint8_t c;
		HAL_StatusTypeDef STATUS = HAL_UART_Receive(&huart1, &c, sizeof(c), 100);
		
		if(STATUS == HAL_OK)
		{
			HAL_UART_Transmit(&huart1, &c, sizeof(c), (uint32_t)-1 );
			
			if(c == 'a'){
				HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5 | GPIO_PIN_6, GPIO_PIN_RESET);
			}
			
			else if(c == 'b'){
				HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5 | GPIO_PIN_6, GPIO_PIN_SET);
			}
			
		}

 

테라텀에서 값을 입력받으면 (a는 점등, b는 소등) led가 반응

 

HAL_ADC_GetValue(&hadc1);
	
	float adc_value = (float)HAL_ADC_Start(&hadc1);
	
	int count = 0;
	while (1)
  {
		adc_value = 0.9 * adc_value + 0.1 * HAL_ADC_GetValue(&hadc1);;
		HAL_Delay(10);
		count = count+1;
		
		
		if((count % 100)==0){
			printf("%d \r\n", (int)(adc_value + 0.5));
		}
		
		
		uint8_t c;
		HAL_StatusTypeDef STATUS = HAL_UART_Receive(&huart1, &c, sizeof(c), 0);
		
		if(STATUS == HAL_OK)
		{
			HAL_UART_Transmit(&huart1, &c, sizeof(c), (uint32_t)-1 );
			
			if(c == 'a'){
				HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5 | GPIO_PIN_6, GPIO_PIN_RESET);
			}
			
			else if(c == 'b'){
				HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5 | GPIO_PIN_6, GPIO_PIN_SET);
			}
		}

 

테라텀에 A입력 시 LED 점등, B입력 시 LED 소등 / 또한 조도센서에서 입력받는 값을 테라텀에 출력한다.

 

 

 

Counter period = ARR

Pulse = CCR

위 함수를 이용해 pwm 생성

 

CCR값을 변해줬을 때 LED의 밝기가 극명하게 변한다.

 

GPIOA->ODR = GPIOA->ODR & ~ (0x1 << 5);
	int bright = 499;
	while (1)
  {
uint8_t c;
		HAL_StatusTypeDef STATUS = HAL_UART_Receive(&huart1, &c, sizeof(c), 0);
		
		if(STATUS == HAL_OK)
		{
			HAL_UART_Transmit(&huart1, &c, sizeof(c), (uint32_t)-1 );
			
			if(c == 'a'){
				
				bright += 50;
				if(bright > 999)
					bright = 999;
				
				__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, bright); 
				printf("%d \r\n",bright);
			}
			
			else if(c == 'b'){
				
				bright -= 50;
				if(bright < 0)
					bright = 0;
				
				__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, bright); 
				printf("%d \r\n",bright);
			}
		}

Led의 핀 밝기를 PWMCCR값을 조절해서 조절한다.