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

Tôi hiểu rằng nhiều tác vụ có thể cố gắng sử dụng tài nguyên SPI. spiTxRxByteCount là một biến toàn cầu được sử dụng để theo dõi xem SPI hiện đang được sử dụng bởi một nhiệm vụ khác hay không. Khi một nhiệm vụ yêu cầu SPI, nó có thể kiểm tra trạng thái của spiTxRxByteCount để xem liệu SPI có đang được sử dụng hay không. Khi một nhiệm vụ được thực hiện bằng cách sử dụng SPI nó gọi hàm này và xóa bit, để chỉ ra rằng SPI bây giờ là miễn phí. Nhưng tại sao vô hiệu hóa các ngắt đầu tiên và sau đó kích hoạt lại chúng sau? Chỉ là hoang tưởng?Tại sao vô hiệu hóa ngắt ở đây?

+0

Nếu bạn có RTOS, tại sao không sử dụng mutex? –

+0

@ [Hoạt động semaphore được thực hiện theo cách này trong hệ điều hành] (http://www.mpi-sws.org/~druschel/courses/os/lectures/proc4.pdf) –

Trả lời

14

& = sẽ thực hiện thao tác đọc-sửa-ghi - nó không phải là nguyên tử. Bạn không muốn một sự thay đổi gián đoạn những điều ở giữa đó, kết quả là viết over-writing với một giá trị không chính xác.

8

Bạn cần vô hiệu hóa ngắt để đảm bảo truy cập nguyên tử. Bạn không muốn bất kỳ quy trình nào khác truy cập và có khả năng sửa đổi biến đó khi bạn đang đọc nó.

Từ Introduction to Embedded Computing:

Nhu cầu truy cập Atomic

Hãy tưởng tượng kịch bản này: Chương trình foreground, chạy trên một 8-bit UC, nhu cầu để kiểm tra một biến 16-bit, gọi nó là X Vì vậy, nó tải cao byte và sau đó tải byte thấp (hoặc cách khác xung quanh, thứ tự không quan trọng), và sau đó kiểm tra giá trị 16-bit. Bây giờ hãy tưởng tượng một ngắt với một ISR liên quan để sửa đổi biến 16 bit đó. Hãy tưởng tượng thêm rằng giá trị của biến xảy ra là 0x1234 tại một thời gian nhất định trong quá trình thực thi chương trình. Dưới đây là Very Bad Thing có thể xảy ra:

  • tải foreground byte cao (0x12)
  • ISR xảy ra, sẽ thay đổi X để 0xABCD
  • tải foreground byte thấp (0xCD)
  • chương trình foreground thấy giá trị 16 bit của 0x12CD.

Vấn đề là một mảnh được cho là bất khả phân của dữ liệu, biến X của chúng tôi, thực sự đã được sửa đổi trong quá trình truy cập vào nó, vì các hướng dẫn CPU để truy cập biến là chia hết cho. Và do đó tải của chúng tôi về biến X đã bị hỏng. Bạn có thể thấy rằng thứ tự của biến đọc không quan trọng. Nếu đơn đặt hàng được đảo ngược trong ví dụ của chúng tôi, biến sẽ không được đọc sai dưới dạng 0xAB34 thay vì 0x12CD. Dù bằng cách nào, giá trị được đọc không phải là giá trị hợp lệ cũ (0x1234) hoặc giá trị hợp lệ mới (0xABCD).

Viết dữ liệu tham chiếu ISR không tốt hơn. Thời gian này giả định rằng chương trình tiền cảnh đã được viết, vì lợi ích của ISR, giá trị trước đó là 0x1234 và sau đó cần phải viết một giá trị 0xABCD mới.Trong trường hợp này, VBT được như sau:

  • cửa hàng foreground mới byte cao (0xAB)
  • ISR xảy ra, đọc X như 0xAB34
  • cửa hàng foreground mới byte thấp (0xCD)

Một lần nữa mã (lần này là ISR) không thấy giá trị hợp lệ trước đây là 0x1234, cũng như giá trị hợp lệ mới của 0xABCD, nhưng thay vì giá trị không hợp lệ của 0xAB34.

Trong khi spiTxRxByteCount &= ~0x0100; có thể trông giống như một hướng dẫn trong C, thực ra nó là một vài hướng dẫn cho CPU. Biên soạn trong GCC, việc niêm yết lắp ráp trông giống như vậy:

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 

Nếu một ngắt được lấy ở giữa bất kỳ của những hướng dẫn và sửa đổi các dữ liệu, ISR đầu tiên của bạn có khả năng có thể đọc các giá trị sai. Vì vậy, bạn cần phải vô hiệu hóa ngắt trước khi bạn hoạt động trên nó và cũng tuyên bố biến volatile.