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:
Ibrahim Abdelkader 2024-01-26 19:47:32 +02:00 committed by GitHub
commit 0afc4c6574
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 74 additions and 92 deletions

View File

@ -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();

View File

@ -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) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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;
HAL_DMA_Abort(&DMAHandle);
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
if (in_irq) {
HAL_DMA_Abort_IT(&DMAHandle);
} else {
HAL_DMA_Abort(&DMAHandle);
}
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
HAL_MDMA_Abort(&DCMI_MDMA_Handle0);
HAL_MDMA_Abort(&DCMI_MDMA_Handle1);
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.