STM32F7 bị kẹt trong chức năng gọi lại ngắt bên ngoài


7

Tôi đang làm việc trên một dự án để kết nối máy ảnh với bảng Discovery STM32F7 bằng giao diện DCMI. Phần camera hoạt động tốt, nhưng tôi có một vấn đề kỳ lạ với các ngắt bên ngoài từ nút ấn trên bo mạch.

Tôi kích hoạt các ngắt ngoài cho nút bằng chức năng được cung cấp trong gói STM BSP:

BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);

Ngắt bên ngoài cho nút này hiện có trên GPIO_PIN_11. Ngắt này được xử lý bởi hàm HAL_GPIO_EXTI_Callback mà tôi có thể thực hiện trong tệp main.c của mình.

Tôi đang sử dụng thư viện STM HAL / BSP.

Ngắt trên một nút nhấn hoạt động và chức năng gọi lại được nhập chính xác, nhưng đây là nơi vấn đề bắt đầu.

Đây là những gì tôi muốn làm trên một nút nhấn:

{
        if(capture_status == 0)
        {
            start_capture_continuous((uint8_t*)CAMERA_FRAME_BUFFER);//start continuous grabbing, if not already running
            if(suspended == 1)
            {
                Camera_Resume();//resume DCMI and DMA if necessary and wakeup sensor from standby
            }
        }
        else
        {
            Camera_status = stop_capture();//stop if already running and update the status
            Camera_Suspend();//halt DCMI and DMA and put sensor in standby mode
        }
    HAL_Delay(50);
}

Giải thích về mã này:

Mã này là để chuyển đổi chế độ xem trước trực tiếp của máy ảnh trên màn hình LCD.

start_capture_continuous((uint8_t*)CAMERA_FRAME_BUFFER);

Chức năng này bắt đầu lấy liên tục các khung hình từ máy ảnh và cập nhật bộ đệm khung. Về cơ bản, nó tham chiếu hàm HAL_DCMI_Start_DMA.

stop_capture();

Chức năng này dừng chuyển DMA.

Camera_Suspend và Camera_Resume tắt / bật giao diện DCMI và gửi lệnh chờ / đánh thức đến cảm biến máy ảnh của tôi thông qua I2C.

Vì vậy, đây là nơi vấn đề bắt đầu:

Nếu tôi đặt mã này vào chức năng gọi lại, MCU sẽ bị kẹt ở đâu đó trong chức năng này. Chỉ cần thiết lập lại có thể đưa tôi trở lại trạng thái bình thường.

Ở đâu đó trên internet tôi đọc được rằng vấn đề này có thể liên quan đến I2C, nhưng ngay cả khi tôi xóa các phần I2C trong chức năng gọi lại, hành vi không như mong muốn: Đôi khi nó hoạt động khoảng ba lần hoặc nó bị kẹt lại ngay lập tức. Tôi tin rằng vấn đề nằm ở hàm HAL_DCMI_Start_DMA, nhưng tôi không chắc chắn.

Có bất kỳ sai lầm phổ biến dẫn đến một vấn đề như thế này?

Tôi hy vọng đã trở nên rõ ràng vấn đề của tôi là gì và ai đó có thể cho tôi một số gợi ý để giải quyết nó.

btw: Nếu tôi sử dụng nút trong chế độ bỏ phiếu trong vòng lặp vô hạn chính và thực hiện chính xác những điều tương tự trên một nút bấm, mọi thứ đều hoạt động tốt.

Để làm rõ các thói quen gián đoạn của tôi:

Xử lý ngắt chính:

void EXTI15_10_IRQHandler(void)
{
//if button pressed
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_11) != RESET)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
}
//if touchscreen interrupt
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_13) != RESET)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
}

các cuộc gọi:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}

các cuộc gọi sau khi đặt lại cờ IT:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
sprintf((char*)text, "EXTI pin: %d", GPIO_Pin);
BSP_LCD_DisplayStringAt(5, LINE(8), (uint8_t*)text, LEFT_MODE);
//if button pressed -> toggle preview
if(GPIO_Pin == GPIO_PIN_11)
{
    BSP_LED_Toggle(LED1);
}
//ts interrupt
if(GPIO_Pin == GPIO_PIN_13)
{

}
}

Điều này hoạt động hoàn hảo, nhưng nếu tôi thay thế BSP_LED_Toggle (LED1); với mã ở trên, chức năng bị kẹt.

Cập nhật: Tôi tìm thấy sai lầm. Ưu tiên ngắt SysTick được đặt ở mức thấp nhất (15), do đó, việc gọi HAL_Delay () từ ISR có cùng mức ưu tiên hoặc cao hơn đã gây ra một vòng lặp vô hạn trong hàm HAL_Delay.

Vì vậy, hãy cẩn thận: Nếu bạn đang sử dụng cài đặt HAL mặc định do ST cung cấp, mức độ ưu tiên cho SysTick IRQ được đặt thành 15 khi gọi HAL_Init (). Bạn phải thay đổi điều đó trong tệp stm32f7xx_hal_conf.h hoặc bằng cách sử dụng chức năng HAL_InitTick (TickP Warriority).

Dưới đây là những gì tài liệu HAL của HAL_InitTick nói về vấn đề đó:

Phải cẩn thận nếu HAL_Delay () được gọi từ quy trình ISR ngoại vi, Ngắt SysTick phải có mức ưu tiên cao hơn (thấp hơn về số) so với ngắt ngoại vi. Nếu không, quá trình ISR của người gọi sẽ bị chặn. Hàm được khai báo là __weak được ghi đè trong trường hợp thực hiện khác trong tệp người dùng.


1
Bạn đã bao gồm mã để xóa cờ ngắt bên trong trình xử lý / gọi lại của bạn chưa?
SoreDakeNoKoto

2
Đó là một tấn công việc phải làm trong một gián đoạn, và thực hành xấu. Đặt cờ trong ngắt và tác động lên cờ chính.
Scott Seidman

Tôi biết đây là thực hành tồi, nhưng dường như đây là cách thực hành chuẩn của thư viện ST HAL. Trình xử lý chính là hàm EXTI15_10_IRQHandler (void) trong tệp stm32f7xx_it.c. Hàm này kiểm tra xem GPIO nào ghim ngắt xảy ra và gọi HAL_GPIO_EXTI_IRQHandler (GPIO_PIN_11). Cờ ngắt được xóa trong hàm HAL, hàm này cũng gọi hàm gọi lại sau đó. Vì vậy, thủ tục thực sự phức tạp hơn khi cần thiết nhưng vấn đề không nằm ở việc xóa cờ ngắt.
deinoppa

Chương trình nào bạn đang sử dụng để gỡ lỗi? Tôi đã gặp vấn đề tương tự một lần và phải sửa những gì tôi nghĩ đó là lỗi thư viện ST HAL. Nhưng để tìm hiểu cụ thể nơi chương trình của tôi bị kẹt, tôi đã sử dụng Visual Studio với VisualGDB, thật khó để xác định chính xác vấn đề của bạn mà không cần gỡ lỗi từng bước. Nếu tôi có thể tìm thấy nơi tôi đã thay đổi mã, tôi sẽ trả lời với nó, nhưng tôi không chắc nó sẽ giải quyết vấn đề của bạn.
FMarazzi

1
Bạn nên đăng giải pháp của mình và biến nó thành câu trả lời được chấp nhận để mọi người không lãng phí thời gian đọc nó.
Tut

Câu trả lời:


7

Cập nhật: Tôi tìm thấy sai lầm. Ưu tiên ngắt SysTick được đặt ở mức thấp nhất (15), do đó, việc gọi HAL_Delay () từ ISR có cùng mức ưu tiên hoặc cao hơn đã gây ra một vòng lặp vô hạn trong hàm HAL_Delay.

Vì vậy, hãy cẩn thận: Nếu bạn đang sử dụng cài đặt HAL mặc định do ST cung cấp, mức độ ưu tiên cho SysTick IRQ được đặt thành 15 khi gọi HAL_Init (). Bạn phải thay đổi điều đó trong tệp stm32f7xx_hal_conf.h hoặc bằng cách sử dụng chức năng HAL_InitTick (TickP Warriority).

Dưới đây là những gì tài liệu HAL của HAL_InitTick nói về vấn đề đó:

Phải cẩn thận nếu HAL_Delay () được gọi từ quy trình ISR ngoại vi, Ngắt SysTick phải có mức ưu tiên cao hơn (thấp hơn về số) so với ngắt ngoại vi. Nếu không, quá trình ISR của người gọi sẽ bị chặn. Hàm được khai báo là __weak được ghi đè trong trường hợp thực hiện khác trong tệp người dùng.


1

Giả sử rằng mã không bị kẹt trong ISR (theo tuyên bố cuối cùng của bạn, điều đó dường như không thể xảy ra), mã không xóa cờ ngắt bên trong thói quen dịch vụ ngắt. Khi ISR ​​thoát, vi điều khiển sẽ "thấy" rằng cờ ngắt vẫn được đặt và ngay lập tức nhảy trở lại thói quen phục vụ ngắt.

Bạn cần xóa cờ ngắt bên trong thói quen dịch vụ ngắt. Tôi không đủ quen thuộc với STM32 và môi trường phát triển để cho bạn biết chính xác cách xóa cờ ngắt, nhưng cờ ngắt cần phải được xóa bên trong ISR.


Xem bình luận của tôi ở trên. Nếu tôi chỉ bật một đèn LED để ngắt thì mọi thứ đều hoạt động tốt, vì vậy vấn đề rõ ràng không nằm ở việc xóa cờ.
deinoppa

@deinoppa Bạn có thể đăng mã ISR đầy đủ của mình không?
CHendrix

thêm nó trong bài viết gốc
deinoppa

tìm thấy lỗi, xem bài gốc.
deinoppa

2
@deinoppa Tôi khuyên bạn nên đưa mô tả sửa lỗi đó vào câu trả lời và chấp nhận nó.
CHendrix
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.