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.