임베디드

volatile

twoweeks-within 2025. 2. 13. 10:52

최적화방지!

 

 

//16bit 짜리 타이머  

uint8 *TIMER = (uint8_t *)0x8020;

// 8bit 씩 쪼갬

 

1.  (uint8_t *) 로 형변환 하는이유

   : 0x8020 자체는 숫자임

     > 포인터 형태로 바꾸어줘야 해당 주소로 접근 가능     

     > 0x8020란 주소는 이제 8bit 씩 값을 가르킴

 

/*

uint8_t value[2] = {0x0, 0x1};

// 각 요소를 8bit 씩 저장

 

&value[0] = 0000 0000

&value[1] = 0000 0001

 

//

cpu는 메모리를 1byte 씩 접근

>

uint16_t val = 0x0001;

>> (Little Endian)

&val = 0x01

&val+1 = 0x00 

>>>

uint16_t *ptr16 = (uint16_t *)&val; 로 할경우

   > 0x01 , 0x00 : 한번에 2개의 주소를 가져옴

      // 그럼에도 ptr16 은 메모리 1byte 씩 저장

      // <> 읽을때만 16 bit 씩 읽음

*/

 

> 메모리 주소를 가진 I/O는 volatile 로 선언!

 

>>

1. 

uint8_t volatile *TIMER = (uint8_t volatile *)0x8020;

>

어셈블리 코드 변경시 메모리 주소 읽도록  // 컴파일러는 이때 최적화 진행 

  

2. 

a. Interrupt_Handler() 와 main() 내의 해당 함수를 공유하는 변수는 전역변수로 선언

b. 캐싱 (regi 에 넣어두고 빠르게 꺼내씀) 때문에 메모리에서 한번 참조 후에는 재확인x

c. (문제발생)

Interrupt / main 에서의 register 가 다름 by Context Changing

  > 각각 함수 내에서 변수의 값이 바뀌더라도 공유가 안됨

>>

d. (해결)

항상 메모리를 참조 하도록 Volatile 로 선언!

 

3. 멀티 쓰레드 

 이때도 Context_Changing 발생 ! > 다른 레지스터 사용 

 

4. 예외의 상황

 

void delay(){ 카운트 증가하는 for문~ }

 

int main(){

 

PORTA = 0x00;

delay(100);

PORTA = 0xff;

}

> 컴파일러 입장에서는 0x00 > delay(100) 동안에 값 바뀐게 X 

    > PORTA = 0xff 만 하도록 최적화 할 수 있음

    > 이를 방지: Volatile

 

 

총정리)

 

1. 메모리 > 레지스터 > cpu 

2. 이때 컴파일러는 캐싱, 최적화 진행 // 자주 쓰는건 regi 유지

3. 메모리의 값 변경 확인 놓칠 수 있음

4. voliatile 로 선언 > 계속 메모리에서 확인하도록함

 

'임베디드' 카테고리의 다른 글

게획) SBC, MCU, FPGA  (0) 2025.01.29