2012-11-28 4 views
7
static void RadioReleaseSPI(void) { 
    __disable_interrupt(); 
    spiTxRxByteCount &= ~0x0100; 
    __enable_interrupt(); 
} 

여러 작업에서 SPI 리소스를 사용하려고 시도하는 것으로 알고 있습니다. spiTxRxByteCount은 SPI가 현재 다른 작업에서 사용되고 있는지 여부를 추적하는 데 사용되는 전역 변수입니다. 태스크가 SPI를 필요로 할 때 spiTxRxByteCount의 상태를 점검하여 SPI가 사용 중인지 확인할 수 있습니다. SPI를 사용하여 작업이 완료되면이 함수를 호출하고 비트를 지우고 SPI가 현재 비어 있음을 나타냅니다. 하지만 왜 인터럽트를 먼저 비활성화 한 후 다시 활성화해야합니까? 편집증 일 뿐이야?여기서 인터럽트를 비활성화해야하는 이유는 무엇입니까?

+0

RTOS가 있다면 뮤텍스를 사용하지 않으시겠습니까? –

+0

@ [OS에서 이런 식으로 구현 된 세마포어 작업] (http://www.mpi-sws.org/~druschel/courses/os/lectures/proc4.pdf) –

답변

14

& = 읽기 - 수정 - 쓰기 작업을 수행합니다. 이는 원자 적이지 않습니다. 그 중간에 인터럽트를 변경하는 인터럽트를 원하지 않으므로 잘못된 값으로 쓰기 덮어 쓰기가 발생합니다.

8

원자 적 액세스를 보장하려면 인터럽트를 비활성화해야합니다. 다른 프로세스가 읽고 읽는 동안 해당 변수에 액세스하고 잠재적으로 수정할 수 없기를 바랍니다. Introduction to Embedded Computing에서

: 원자 액세스에 대한

의 필요성

이 시나리오 상상 : X를, 16 비트 변수를 검토 전경 프로그램, 8 비트 uc에, 필요에 실행을 호출 그래서 높은 바이트를로드 한 다음 낮은 바이트를로드합니다 (또는 다른 방법으로는 은 중요하지 않음). 그런 다음 16 비트 값을 검사합니다. 이제 해당 16 비트 변수를 수정하는 연관된 ISR로 인터럽트를 상상해보십시오. 또한 변수의 값이 프로그램 실행의 주어진 시간 인 에서 0x1234가된다고 상상해보십시오. ,

  • 전경 부하 상위 바이트 (0x12를)
  • ISR가 발생합니다
  • 전경 프로그램을보고 0xABCD
  • 전경 부하 하위 바이트 (0XCD)에 X를 수정 : 여기에 일어날 수있는 아주 나쁜 것 입니다 0x12CD의 16 비트 값

문제는 데이터의 가정 불가분 편 우리 변수 X는, 실제로 변수를 액세스하기위한 CPU 명령어 나누어 질 수 있기 때문에, 액세스 과정에서 수정 된 것이다. 따라서 변수 X의로드가 손상되었습니다. 변수 읽기 순서가 중요하지 않음을 알 수 있습니다. 예제에서 의 순서가 바뀐 경우 변수는 0x35CD 대신 0x3534로 잘못 입력되어 으로 잘못 읽었을 것입니다. 어느 쪽이든 읽을 값은 이전 유효한 값 (0x1234)도 새 유효한 값 (0xABCD)도 아닙니다.

ISR 참조 데이터를 쓰는 것이 더 좋지 않습니다. 이번에는 전경 프로그램이 ISR의 이익을 위해 이전 값 0x1234를 작성한 다음 새 값 0xABCD를 작성해야한다고 가정합니다.이 경우 에서 VBT은 다음과 같다 :

  • 전경 저장 새로운 상위 바이트 (확인 0xAB)
  • ISR 발생은 0xAB34로 X를 판독
  • 전경 저장 새로운 하위 바이트 (0XCD)

다시 한 번 코드 (이번 ISR)는 이전의 유효한 값도 0x1234도 아니고 0xABCD의 새 유효한 값도 아니지만 0xAB34의 잘못된 값을 봅니다.

spiTxRxByteCount &= ~0x0100;은 C에서 단일 명령어처럼 보일 수 있지만 실제로 CPU에 대한 몇 가지 명령어입니다. GCC에서 컴파일 된 어셈블리 목록이 너무과 같습니다 인터럽트의 사이에 그 명령어의 제공과 데이터를 수정

57:atomic.c  ****  spiTxRxByteCount &= ~0x0100; 
    68     .loc 1 57 0 
    69 004d A1000000  movl _spiTxRxByteCount, %eax 
    69  00 
    70 0052 80E4FE  andb $254, %ah 
    71 0055 A3000000  movl %eax, _spiTxRxByteCount 
    71  00 

경우, 첫 번째 ISR은 잠재적으로 잘못된 값을 읽을 수 있습니다. 따라서 인터럽트를 실행하기 전에 인터럽트를 비활성화하고 변수 volatile을 선언해야합니다.