mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #2116 from openmv/sensor_abort_args
ports/all: Allow sensor_abort() to be called from different contexts.
This commit is contained in:
commit
0afc4c6574
@ -299,7 +299,7 @@ int sensor_probe_init(uint32_t bus_id, uint32_t bus_speed);
|
||||
int sensor_dcmi_config(uint32_t pixformat);
|
||||
|
||||
// Abort frame capture and disable IRQs, DMA etc..
|
||||
int sensor_abort();
|
||||
int sensor_abort(bool fifo_flush, bool in_irq);
|
||||
|
||||
// Reset the sensor to its default state.
|
||||
int sensor_reset();
|
||||
|
||||
@ -101,13 +101,13 @@ __weak int sensor_init() {
|
||||
return SENSOR_ERROR_CTL_UNSUPPORTED;
|
||||
}
|
||||
|
||||
__weak int sensor_abort() {
|
||||
__weak int sensor_abort(bool fifo_flush, bool in_irq) {
|
||||
return SENSOR_ERROR_CTL_UNSUPPORTED;
|
||||
}
|
||||
|
||||
__weak int sensor_reset() {
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Reset the sensor state
|
||||
sensor.sde = 0;
|
||||
@ -164,7 +164,7 @@ __weak int sensor_reset() {
|
||||
}
|
||||
|
||||
// Reset framebuffers
|
||||
framebuffer_reset_buffers();
|
||||
framebuffer_flush_buffers(true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -472,7 +472,7 @@ __weak bool sensor_is_detected() {
|
||||
|
||||
__weak int sensor_sleep(int enable) {
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Check if the control is supported.
|
||||
if (sensor.sleep == NULL) {
|
||||
@ -491,7 +491,7 @@ __weak int sensor_shutdown(int enable) {
|
||||
int ret = 0;
|
||||
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
#if defined(DCMI_POWER_PIN)
|
||||
if (enable) {
|
||||
@ -568,7 +568,7 @@ __weak int sensor_set_pixformat(pixformat_t pixformat) {
|
||||
}
|
||||
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Flush previous frame.
|
||||
framebuffer_update_jpeg_buffer();
|
||||
@ -607,7 +607,7 @@ __weak int sensor_set_framesize(framesize_t framesize) {
|
||||
}
|
||||
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Flush previous frame.
|
||||
framebuffer_update_jpeg_buffer();
|
||||
@ -715,7 +715,7 @@ __weak int sensor_set_windowing(int x, int y, int w, int h) {
|
||||
}
|
||||
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Flush previous frame.
|
||||
framebuffer_update_jpeg_buffer();
|
||||
@ -945,7 +945,7 @@ __weak int sensor_set_hmirror(int enable) {
|
||||
}
|
||||
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Check if the control is supported.
|
||||
if (sensor.set_hmirror == NULL) {
|
||||
@ -979,7 +979,7 @@ __weak int sensor_set_vflip(int enable) {
|
||||
}
|
||||
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Check if the control is supported.
|
||||
if (sensor.set_vflip == NULL) {
|
||||
@ -1013,7 +1013,7 @@ __weak int sensor_set_transpose(bool enable) {
|
||||
}
|
||||
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
if (sensor.pixformat == PIXFORMAT_JPEG) {
|
||||
return SENSOR_ERROR_PIXFORMAT_UNSUPPORTED;
|
||||
@ -1036,7 +1036,7 @@ __weak int sensor_set_auto_rotation(bool enable) {
|
||||
}
|
||||
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Operation not supported on JPEG images.
|
||||
if (sensor.pixformat == PIXFORMAT_JPEG) {
|
||||
@ -1054,7 +1054,7 @@ __weak bool sensor_get_auto_rotation() {
|
||||
|
||||
__weak int sensor_set_framebuffers(int count) {
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Flush previous frame.
|
||||
framebuffer_update_jpeg_buffer();
|
||||
@ -1100,7 +1100,7 @@ __weak int sensor_set_lens_correction(int enable, int radi, int coef) {
|
||||
|
||||
__weak int sensor_ioctl(int request, ... /* arg */) {
|
||||
// Disable any ongoing frame capture.
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Check if the control is supported.
|
||||
if (sensor.ioctl == NULL) {
|
||||
|
||||
@ -274,7 +274,13 @@ vbuffer_t *framebuffer_get_buffer(int32_t index) {
|
||||
return (vbuffer_t *) (framebuffer->data + offset);
|
||||
}
|
||||
|
||||
void framebuffer_flush_buffers() {
|
||||
void framebuffer_flush_buffers(bool fifo_flush) {
|
||||
if (fifo_flush) {
|
||||
// Drop all frame buffers.
|
||||
for (int32_t i = 0; i < framebuffer->n_buffers; i++) {
|
||||
memset(framebuffer_get_buffer(i), 0, sizeof(vbuffer_t));
|
||||
}
|
||||
}
|
||||
// Move the tail pointer to the head which empties the virtual fifo while keeping the same
|
||||
// position of the current frame for the rest of the code.
|
||||
framebuffer->tail = framebuffer->head;
|
||||
@ -282,14 +288,6 @@ void framebuffer_flush_buffers() {
|
||||
framebuffer->sampled_head = 0;
|
||||
}
|
||||
|
||||
void framebuffer_reset_buffers() {
|
||||
for (int32_t i = 0; i < framebuffer->n_buffers; i++) {
|
||||
memset(framebuffer_get_buffer(i), 0, sizeof(vbuffer_t));
|
||||
}
|
||||
|
||||
framebuffer_flush_buffers();
|
||||
}
|
||||
|
||||
int framebuffer_set_buffers(int32_t n_buffers) {
|
||||
uint32_t total_size = framebuffer_raw_buffer_size();
|
||||
uint32_t size = total_size / n_buffers;
|
||||
@ -307,7 +305,7 @@ int framebuffer_set_buffers(int32_t n_buffers) {
|
||||
framebuffer->n_buffers = n_buffers;
|
||||
framebuffer->head = 0;
|
||||
|
||||
framebuffer_reset_buffers();
|
||||
framebuffer_flush_buffers(true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -101,11 +101,9 @@ void framebuffer_init_from_image(image_t *img);
|
||||
// if the src is JPEG and fits in the JPEG buffer, or encode and stream src image to the IDE if not.
|
||||
void framebuffer_update_jpeg_buffer();
|
||||
|
||||
// Clears out all old captures frames in the framebuffer.
|
||||
void framebuffer_flush_buffers();
|
||||
|
||||
// Resets all buffers (for use after aborting)
|
||||
void framebuffer_reset_buffers();
|
||||
// Clear the framebuffer FIFO. If fifo_flush is true, reset and discard all framebuffers,
|
||||
// otherwise, retain the last frame in the fifo.
|
||||
void framebuffer_flush_buffers(bool fifo_flush);
|
||||
|
||||
// Controls the number of virtual buffers in the frame buffer.
|
||||
int framebuffer_set_buffers(int32_t n_buffers);
|
||||
|
||||
@ -49,7 +49,7 @@ static bool drop_frame = false;
|
||||
}
|
||||
|
||||
void sensor_init0() {
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Re-init I2C to reset the bus state after soft reset, which
|
||||
// could have interrupted the bus in the middle of a transfer.
|
||||
@ -151,7 +151,7 @@ int sensor_dcmi_config(uint32_t pixformat) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sensor_abort() {
|
||||
int sensor_abort(bool fifo_flush, bool in_irq) {
|
||||
NVIC_DisableIRQ(CSI_IRQn);
|
||||
CSI_DisableInterrupts(CSI, CSI_IRQ_FLAGS);
|
||||
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
||||
@ -160,7 +160,11 @@ int sensor_abort() {
|
||||
drop_frame = false;
|
||||
sensor.last_frame_ms = 0;
|
||||
sensor.last_frame_ms_valid = false;
|
||||
framebuffer_reset_buffers();
|
||||
if (fifo_flush) {
|
||||
framebuffer_flush_buffers(true);
|
||||
} else if (!sensor.disable_full_flush) {
|
||||
framebuffer_flush_buffers(false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -191,20 +195,7 @@ void sensor_sof_callback() {
|
||||
// Get current framebuffer.
|
||||
vbuffer_t *buffer = framebuffer_get_tail(FB_PEEK);
|
||||
if (buffer == NULL) {
|
||||
// Do not call abort here as it calls framebuffer_reset_buffers() which will invalidate
|
||||
// all the frame buffers. framebuffer_flush_buffers() keeps the latest frame.
|
||||
NVIC_DisableIRQ(CSI_IRQn);
|
||||
CSI_DisableInterrupts(CSI, CSI_IRQ_FLAGS);
|
||||
CSI_REG_CR3(CSI) &= ~CSI_CR3_DMA_REQ_EN_RFF_MASK;
|
||||
CSI_REG_CR18(CSI) &= ~CSI_CR18_CSI_ENABLE_MASK;
|
||||
first_line = false;
|
||||
drop_frame = false;
|
||||
sensor.last_frame_ms = 0;
|
||||
sensor.last_frame_ms_valid = false;
|
||||
// Reset the queue of frames when we start dropping frames.
|
||||
if (!sensor.disable_full_flush) {
|
||||
framebuffer_flush_buffers();
|
||||
}
|
||||
sensor_abort(false, true);
|
||||
} else if (buffer->offset < resolution[sensor.framesize][1]) {
|
||||
// Missed a few lines, reset buffer state and continue.
|
||||
buffer->reset_state = true;
|
||||
@ -445,7 +436,7 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
||||
for (mp_uint_t ticks = mp_hal_ticks_ms(); buffer == NULL;) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
if ((mp_hal_ticks_ms() - ticks) > 3000) {
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
#if defined(DCMI_FSYNC_PIN)
|
||||
if (sensor->hw_flags.fsync) {
|
||||
|
||||
@ -137,7 +137,7 @@ int sensor_init() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sensor_abort() {
|
||||
int sensor_abort(bool fifo_flush, bool in_irq) {
|
||||
// Disable DMA channel
|
||||
dma_channel_abort(DCMI_DMA_CHANNEL);
|
||||
dma_irqn_set_channel_enabled(DCMI_DMA, DCMI_DMA_CHANNEL, false);
|
||||
@ -249,7 +249,7 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
||||
for (mp_uint_t ticks = mp_hal_ticks_ms(); buffer == NULL;) {
|
||||
buffer = framebuffer_get_head(FB_NO_FLAGS);
|
||||
if ((mp_hal_ticks_ms() - ticks) > 3000) {
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
return SENSOR_ERROR_CAPTURE_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,9 +97,8 @@ static int sensor_dma_config() {
|
||||
// Set DMA IRQ handle
|
||||
dma_utils_set_irq_descr(DMA2_Stream1, &DMAHandle);
|
||||
|
||||
// Configure and enable DMA IRQ Channel
|
||||
// Configure the DMA IRQ Channel
|
||||
NVIC_SetPriority(DMA2_Stream1_IRQn, IRQ_PRI_DMA21);
|
||||
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -109,7 +108,7 @@ void sensor_init0() {
|
||||
DCMI_MDMA_Handle1.Instance = MDMA_CHAN_TO_INSTANCE(OMV_MDMA_CHANNEL_DCMI_1);
|
||||
#endif
|
||||
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
// Re-init i2c bus to reset the bus state after soft reset, which
|
||||
// could have interrupted the bus in the middle of a transfer.
|
||||
@ -229,16 +228,22 @@ int sensor_dcmi_config(uint32_t pixformat) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sensor_abort() {
|
||||
int sensor_abort(bool fifo_flush, bool in_irq) {
|
||||
// This stops the DCMI hardware from generating DMA requests immediately and then stops the DMA
|
||||
// hardware. Note that HAL_DMA_Abort is a blocking operation. Do not use this in an interrupt.
|
||||
if (DCMI->CR & DCMI_CR_ENABLE) {
|
||||
DCMI->CR &= ~DCMI_CR_ENABLE;
|
||||
if (in_irq) {
|
||||
HAL_DMA_Abort_IT(&DMAHandle);
|
||||
} else {
|
||||
HAL_DMA_Abort(&DMAHandle);
|
||||
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
|
||||
}
|
||||
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
||||
if (!in_irq) {
|
||||
HAL_MDMA_Abort(&DCMI_MDMA_Handle0);
|
||||
HAL_MDMA_Abort(&DCMI_MDMA_Handle1);
|
||||
}
|
||||
HAL_MDMA_DeInit(&DCMI_MDMA_Handle0);
|
||||
HAL_MDMA_DeInit(&DCMI_MDMA_Handle1);
|
||||
#endif
|
||||
@ -250,7 +255,11 @@ int sensor_abort() {
|
||||
sensor.last_frame_ms_valid = false;
|
||||
}
|
||||
|
||||
framebuffer_reset_buffers();
|
||||
if (fifo_flush) {
|
||||
framebuffer_flush_buffers(true);
|
||||
} else if (!sensor.disable_full_flush) {
|
||||
framebuffer_flush_buffers(false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -321,7 +330,7 @@ int sensor_set_xclk_frequency(uint32_t frequency) {
|
||||
|
||||
int sensor_shutdown(int enable) {
|
||||
int ret = 0;
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
if (enable) {
|
||||
#if defined(DCMI_POWER_PIN)
|
||||
@ -474,22 +483,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
||||
// If snapshot was not already waiting to receive data then we have missed this frame and have
|
||||
// to drop it. So, abort this and future transfers. Snapshot will restart the process.
|
||||
if (!buffer) {
|
||||
DCMI->CR &= ~DCMI_CR_ENABLE;
|
||||
HAL_DMA_Abort_IT(&DMAHandle); // Note: Use HAL_DMA_Abort_IT and not HAL_DMA_Abort inside an interrupt.
|
||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
||||
HAL_MDMA_DeInit(&DCMI_MDMA_Handle0);
|
||||
HAL_MDMA_DeInit(&DCMI_MDMA_Handle1);
|
||||
#endif
|
||||
__HAL_DCMI_DISABLE_IT(&DCMIHandle, DCMI_IT_FRAME);
|
||||
__HAL_DCMI_CLEAR_FLAG(&DCMIHandle, DCMI_FLAG_FRAMERI);
|
||||
first_line = false;
|
||||
drop_frame = false;
|
||||
sensor.last_frame_ms = 0;
|
||||
sensor.last_frame_ms_valid = false;
|
||||
// Reset the queue of frames when we start dropping frames.
|
||||
if (!sensor.disable_full_flush) {
|
||||
framebuffer_flush_buffers();
|
||||
}
|
||||
sensor_abort(false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -768,12 +762,13 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
||||
// case. We know the transfer was stopped by checking DCMI_CR_ENABLE.
|
||||
framebuffer_free_current_buffer();
|
||||
|
||||
// We will be in one of the following states now:
|
||||
// 1. No transfer is currently running right now and DCMI_CR_ENABLE is not set.
|
||||
// 2. A transfer is running and we are waiting for the data to be received.
|
||||
|
||||
// We are not using DCMI_CR_CAPTURE because when this bit is cleared to stop the continuous transfer it does not actually go
|
||||
// low until the end of the frame (yes, you read that right). DCMI_CR_ENABLE stops the capture when cleared and stays low.
|
||||
// We can be in one of the following two states:
|
||||
// 1. No ongoing transfer, and DCMI_CR_ENABLE is cleared.
|
||||
// 2. A transfer is in progress and we are awaiting the reception of data.
|
||||
//
|
||||
// Note that DCMI_CR_CAPTURE is not used because when it's cleared, it does not immediately go
|
||||
// low, instead, it waits until the end of the frame. Conversely, DCMI_CR_ENABLE effectively
|
||||
// aborts the capture when cleared and stays low.
|
||||
//
|
||||
// When DCMI_CR_ENABLE is cleared during a DCMI transfer the hardware will automatically
|
||||
// wait for the start of the next frame when it's re-enabled again below. So, we do not
|
||||
@ -848,14 +843,14 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
||||
// Reset the circular, current target, and double buffer mode flags which get set by the below calls.
|
||||
((DMA_Stream_TypeDef *) DMAHandle.Instance)->CR &= ~(DMA_SxCR_CIRC | DMA_SxCR_CT | DMA_SxCR_DBM);
|
||||
|
||||
// Note that HAL_DCMI_Start_DMA and HAL_DCMI_Start_DMA_MB are effectively the same
|
||||
// method. The only difference between them is how large the DMA transfer size gets
|
||||
// set at. For both of them DMA doesn't actually care how much data the DCMI hardware
|
||||
// generates. It's just trying to move fixed size DMA transfers from the DCMI hardware
|
||||
// to one memory address or another memory address. After transferring X bytes to one
|
||||
// address it will switch to the next address and transfer X bytes again. Both of these
|
||||
// methods set the addresses right after each other. So, effectively DMA is just writing
|
||||
// data to a circular buffer with an interrupt every time 1/2 of it is written.
|
||||
// Enable the DMA IRQ before starting the transfer.
|
||||
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
|
||||
|
||||
// Note: HAL_DCMI_Start_DMA and HAL_DCMI_Start_DMA_MB are essentially the same, differing
|
||||
// only in DMA transfer size. After transferring X bytes to one address it will switch to
|
||||
// the next address and transfer X bytes again. Both of these methods set the addresses
|
||||
// right after each other. So, effectively DMA is just writing data to a circular buffer
|
||||
// with an interrupt every time 1/2 of it is written.
|
||||
if ((sensor->pixformat == PIXFORMAT_JPEG) && (sensor->chip_id == OV2640_ID)) {
|
||||
// The JPEG image will be directly transferred to the frame buffer.
|
||||
// The DCMI hardware can transfer up to 524,280 bytes.
|
||||
@ -924,7 +919,7 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
||||
|
||||
// If we haven't exited this loop before the timeout then we need to abort the transfer.
|
||||
if ((HAL_GetTick() - tick_start) > SENSOR_TIMEOUT_MS) {
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
|
||||
#if defined(DCMI_FSYNC_PIN)
|
||||
if (sensor->hw_flags.fsync) {
|
||||
@ -940,7 +935,7 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
||||
// line will contain how many transfers we completed.
|
||||
// The DMA counter must be used to get the number of remaining words to be transferred.
|
||||
if ((sensor->pixformat == PIXFORMAT_JPEG) && (sensor->chip_id == OV2640_ID)) {
|
||||
sensor_abort();
|
||||
sensor_abort(true, false);
|
||||
}
|
||||
|
||||
// We're done receiving data.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user