타이머 인터럽트 (재)
개요
이전에 타이머 인터럽트가 실현되었지만 인터럽트 전, 인터럽트 처리 및 인터럽트 후 컨텍스트 정보는 전혀 고려하지 않았습니다. 즉, 인터럽트가 들어간 후 인터럽트 처리로 레지스터가 파괴 될 가능성이있었습니다. 이전의 예에서는, 거의 타이머 인터럽트의 처리 밖에 없었기 때문에 파괴되는 일도 없고, 파손된 곳에서 어떻게 하지 않았지만, 향후 이 타이머 인터럽트로 thread를 전환하는 것을 생각하면, 문맥을 보존해 둘 필요가 있다.
따라서 컨텍스트를 저장하도록 타이머 인터럽트를 개선합니다. 또한 인터럽트 처리는 다른 스택을 사용하는 개선도 수행합니다.
컨텍스트 저장
컨텍스트 저장은 레지스터 값을 저장하는 것을 의미합니다. atmega328p에는
r0
~ r31
의 32 개의 레지스터가 있습니다. 또한, SREG
라는 플래그 레지스터로 상태를 관리하고 있으므로, 어떻게 하면 된다.이 처리는 인터럽트 벡터에 등록 된 함수로 수행됩니다.
인터럽트 벡터 개선 1
컨텍스트를 저장하도록 인터럽트 벡터의 함수를 변경합니다. 이전에는
start.s
에 함수를 정의했지만 인터럽트 전용 파일 (intr.s)을 준비합니다.intr.s
.global intr_time
.type intr_time, @function
intr_time:
cli
push r31
push r30
push r29
push r28
push r27
push r26
push r25
push r24
push r23
push r22
push r21
push r20
push r19
push r18
push r17
push r16
push r15
push r14
push r13
push r12
push r11
push r10
push r9
push r8
push r7
push r6
push r5
push r4
push r3
push r2
push r1
push r0
in r31, 0x3f ; save SREG to r31
push r31 ; push SREG
rcall t0a ; t0aの呼び出し
pop r31 ; pop SREG to r31
out 0x3f, r31 ; set SREG
pop r0
pop r1
pop r2
pop r3
pop r4
pop r5
pop r6
pop r7
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
pop r16
pop r17
pop r18
pop r19
pop r20
pop r21
pop r22
pop r23
pop r24
pop r25
pop r26
pop r27
pop r28
pop r29
pop r30
pop r31
reti
앞에서 설명한 것처럼 r31에서 r0까지 SREG (플래그 레지스터) 스택에 쌓인 다음 t0a를 호출하고 반환되면 쌓인 순서와 반대로 스택에서 POP합니다. SREG는 메모리 0x3f에 존재합니다 (사양서에서).
이 때의 스택의 모습은 다음과 같습니다.
이와 같이, 인터럽트 처리를 하기 위해, 직전까지 실행하고 있던 메인의 스택을 그대로 이용하고 있다.
인터럽트 벡터 개선 2
위에서 설명한 것처럼 작동하지만 향후 스레드를 구현하는 것을 고려할 때 인터럽트 프로세스는 항상 스레드의 스택을 사용합니다. 실해는 없지만 인터럽트 처리는 전용 스택을 사용하고 싶다. 구체적으로는 다음과 같이 스택을 전환하여 사용하고 싶습니다.
이 예에서는
t0a
를 호출하기 전에 스택을 전환 (intstack)하고 t0a
를 처리 한 후 다시 원래의 스택으로 되돌려 인터럽트 처리를 완료합니다. 이렇게하려면 intrstack
를 링커 스크립트로 정의하십시오.ld.scr
MEMORY{
(略)
ram(rwx) : o = 0x800100, l = 0x800600 - 0x800100
userstack(rw) : o = 0x800600, l = 0x000000
intrstack(rw) : o = 0x800700, l = 0x000000 ; 割り込み用スタック
bootstack(rw) : o = 0x8007fc, l = 0x000000
}
SECTIONS
{
(略)
. = ALIGN(4);
_end = . ;
.userstack : {
_userstack = .;
} > userstack
.intrstack : {
_intrstack = .;
} > intrstack
.bootstack : {
_bootstack = .;
} > bootstack
}
그런 다음 그림과 같이 처리를 수행하기 위해
intr_time
를 다시 씁니다.intr.s
intr_time:
cli
push r31
(略)
push r0
in r31, 0x3f ; SREG
push r31
in r24, 0x3d ; save current sp low to r22
in r25, 0x3e ; save current sp high to r23
ldi r28, lo8(_intrstack) ; save intrrstack lo byte to r28
ldi r29, hi8(_intrstack) ; save intrstack hi byte to r29
out 0x3d, r28 ; save intrstack low ; change sp to intrstack
out 0x3e, r29 ; save intrstack high
push r24 ; 旧SPのlowをintrstackに積む
push r25 ; 旧SPのhiをintrstackに積む
eor r1, r1
rcall t0a
pop r29 ; pop old sp hi from intrstack
pop r28 ; pop old sp low from intrstack
out 0x3d, r28 ; set sp low
out 0x3e, r29 ; set sp high -> change sp to original
pop r31 ; restore SREG to r31
out 0x3f, r31 ; set SREG
pop r0
(略)
pop r31
reti
이 구현은 다음 명령으로 시도 할 수 있습니다.
>git clone https://github.com/hiro4669/iosv.git
>cd iosv
>git branch interpt_ver1 origin/interpt_ver1
>git checkout interpt_ver1
>cd interpt
>make
>make write
Reference
이 문제에 관하여(타이머 인터럽트 (재)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/hiro4669/items/f48835d8178176953660텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)