mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
ports/mimxrt: Enable edma memcpy.
This commit is contained in:
parent
61ec9006bb
commit
63edb776c3
@ -192,7 +192,12 @@
|
|||||||
|
|
||||||
// Camera interface configuration.
|
// Camera interface configuration.
|
||||||
#define OMV_CSI_BASE (CSI)
|
#define OMV_CSI_BASE (CSI)
|
||||||
|
#define OMV_CSI_DMA (DMA0)
|
||||||
|
#define OMV_CSI_DMA_MUX (DMAMUX)
|
||||||
|
#define OMV_CSI_DMA_CHANNEL_START (4U)
|
||||||
|
#define OMV_CSI_DMA_CHANNEL_COUNT (2U)
|
||||||
#define OMV_CSI_XCLK_FREQUENCY (12000000)
|
#define OMV_CSI_XCLK_FREQUENCY (12000000)
|
||||||
|
#define OMV_CSI_DMA_MEMCPY_ENABLE (1)
|
||||||
#define OMV_CSI_HW_SWAP_ENABLE (1)
|
#define OMV_CSI_HW_SWAP_ENABLE (1)
|
||||||
|
|
||||||
#define OMV_CSI_D0_PIN (&omv_pin_DCMI_D0)
|
#define OMV_CSI_D0_PIN (&omv_pin_DCMI_D0)
|
||||||
|
|||||||
@ -24,14 +24,21 @@
|
|||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
#include "unaligned_memcpy.h"
|
#include "unaligned_memcpy.h"
|
||||||
|
|
||||||
|
#define DMA_LENGTH_ALIGNMENT (8)
|
||||||
|
#define SENSOR_TIMEOUT_MS (3000)
|
||||||
|
|
||||||
// Sensor struct.
|
// Sensor struct.
|
||||||
sensor_t sensor = {};
|
sensor_t sensor = {};
|
||||||
extern uint8_t _line_buf[OMV_LINE_BUF_SIZE];
|
extern uint8_t _line_buf[OMV_LINE_BUF_SIZE];
|
||||||
|
|
||||||
|
#if defined(OMV_CSI_DMA)
|
||||||
|
static edma_handle_t CSI_EDMA_Handle[OMV_CSI_DMA_CHANNEL_COUNT];
|
||||||
|
static int src_inc, src_size, dest_inc_size;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CSI_IRQ_FLAGS (CSI_CR1_SOF_INTEN_MASK \
|
#define CSI_IRQ_FLAGS (CSI_CR1_SOF_INTEN_MASK \
|
||||||
| CSI_CR1_FB2_DMA_DONE_INTEN_MASK \
|
| CSI_CR1_FB2_DMA_DONE_INTEN_MASK \
|
||||||
| CSI_CR1_FB1_DMA_DONE_INTEN_MASK)
|
| CSI_CR1_FB1_DMA_DONE_INTEN_MASK)
|
||||||
//CSI_CR1_RF_OR_INTEN_MASK
|
|
||||||
|
|
||||||
void sensor_init0() {
|
void sensor_init0() {
|
||||||
sensor_abort(true, false);
|
sensor_abort(true, false);
|
||||||
@ -187,6 +194,39 @@ void sensor_sof_callback() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(OMV_CSI_DMA)
|
||||||
|
int sensor_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed) {
|
||||||
|
// EMDA will not perform burst transfers for anything less than 32-byte chunks made of four 64-bit
|
||||||
|
// beats. Additionally, the CSI hardware lacks cropping so we cannot align the source address.
|
||||||
|
// Given this, performance will be lacking on cropped images. So much so that we do not use
|
||||||
|
// the EDMA for anything less than 4-byte transfers otherwise you get sensor timeout errors.
|
||||||
|
if (dest_inc_size < 4) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
edma_handle_t *handle = dma;
|
||||||
|
edma_transfer_config_t config;
|
||||||
|
EDMA_PrepareTransferConfig(&config,
|
||||||
|
src, // srcAddr
|
||||||
|
src_size, // srcWidth
|
||||||
|
src_inc, // srcOffset
|
||||||
|
dst, // destAddr
|
||||||
|
transposed ? bpp : dest_inc_size, // destWidth
|
||||||
|
transposed ? (MAIN_FB()->v * bpp) : dest_inc_size, // destOffset
|
||||||
|
MAIN_FB()->u * bpp, // bytesEachRequest
|
||||||
|
MAIN_FB()->u * bpp); // transferBytes
|
||||||
|
|
||||||
|
// Drop the frame if EDMA is not keeping up as the image will be corrupt.
|
||||||
|
if (EDMA_SubmitTransfer(handle, &config) != kStatus_Success) {
|
||||||
|
sensor.drop_frame = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EDMA_TriggerChannelStart(handle->base, handle->channel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void sensor_line_callback(uint32_t addr) {
|
void sensor_line_callback(uint32_t addr) {
|
||||||
// Throttle frames to match the current frame rate.
|
// Throttle frames to match the current frame rate.
|
||||||
sensor_throttle_framerate();
|
sensor_throttle_framerate();
|
||||||
@ -272,8 +312,14 @@ void sensor_line_callback(uint32_t addr) {
|
|||||||
dst += MAIN_FB()->u * bytes_per_pixel * (buffer->offset - MAIN_FB()->y);
|
dst += MAIN_FB()->u * bytes_per_pixel * (buffer->offset - MAIN_FB()->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy line to frame buffer.
|
#if defined(OMV_CSI_DMA)
|
||||||
|
// We're using multiple handles to give each channel the maximum amount of time possible to do the line
|
||||||
|
// transfer. In most situations only one channel will be running at a time. However, if SDRAM is
|
||||||
|
// backedup we don't have to disable the channel if it is flushing trailing data to SDRAM.
|
||||||
|
sensor_copy_line(&CSI_EDMA_Handle[buffer->offset % OMV_CSI_DMA_CHANNEL_COUNT], src, dst);
|
||||||
|
#else
|
||||||
sensor_copy_line(NULL, src, dst);
|
sensor_copy_line(NULL, src, dst);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++buffer->offset == resolution[sensor.framesize][1]) {
|
if (++buffer->offset == resolution[sensor.framesize][1]) {
|
||||||
@ -286,6 +332,46 @@ void sensor_line_callback(uint32_t addr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(OMV_CSI_DMA)
|
||||||
|
static void edma_config(sensor_t *sensor, uint32_t bytes_per_pixel) {
|
||||||
|
uint32_t line_offset_bytes = MAIN_FB()->x * bytes_per_pixel;
|
||||||
|
uint32_t line_width_bytes = MAIN_FB()->u * bytes_per_pixel;
|
||||||
|
|
||||||
|
// YUV422 Source -> Y Destination
|
||||||
|
if ((sensor->pixformat == PIXFORMAT_GRAYSCALE) && (sensor->hw_flags.gs_bpp == 2)) {
|
||||||
|
line_width_bytes /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destination will be 32-byte aligned. So, we just need to breakup the line width into the largest
|
||||||
|
// power of 2. Source may have an offset which further limits this to a sub power of 2.
|
||||||
|
for (int i = 5; i >= 0; i--) {
|
||||||
|
// 16-byte burst is not supported.
|
||||||
|
if ((i != 4) && (!(line_width_bytes % (1 << i)))) {
|
||||||
|
for (int j = i; j >= 0; j--) {
|
||||||
|
// 16-byte burst is not supported.
|
||||||
|
if ((j != 4) && (!(line_offset_bytes % (1 << j)))) {
|
||||||
|
src_inc = src_size = 1 << j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_inc_size = 1 << i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sensor->transpose) {
|
||||||
|
dest_inc_size = bytes_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// YUV422 Source -> Y Destination
|
||||||
|
if ((sensor->pixformat == PIXFORMAT_GRAYSCALE) && (sensor->hw_flags.gs_bpp == 2)) {
|
||||||
|
src_inc = 2;
|
||||||
|
src_size = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// This is the default snapshot function, which can be replaced in sensor_init functions.
|
// This is the default snapshot function, which can be replaced in sensor_init functions.
|
||||||
int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
||||||
// Used to restore MAIN_FB's width and height.
|
// Used to restore MAIN_FB's width and height.
|
||||||
@ -315,13 +401,30 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
|||||||
if (!(CSI->CR18 & CSI_CR18_CSI_ENABLE_MASK)) {
|
if (!(CSI->CR18 & CSI_CR18_CSI_ENABLE_MASK)) {
|
||||||
framebuffer_setup_buffers();
|
framebuffer_setup_buffers();
|
||||||
|
|
||||||
vbuffer_t *buffer = framebuffer_get_tail(FB_PEEK);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
return SENSOR_ERROR_FRAMEBUFFER_ERROR;
|
|
||||||
}
|
|
||||||
// Re/configure and re/start the CSI.
|
// Re/configure and re/start the CSI.
|
||||||
uint32_t bytes_per_pixel = sensor_get_src_bpp();
|
uint32_t bytes_per_pixel = sensor_get_src_bpp();
|
||||||
uint32_t dma_line_bytes = resolution[sensor->framesize][0] * bytes_per_pixel;
|
uint32_t dma_line_bytes = resolution[sensor->framesize][0] * bytes_per_pixel;
|
||||||
|
uint32_t length = dma_line_bytes * h;
|
||||||
|
|
||||||
|
// Error out if the transfer size is not compatible with DMA transfer restrictions.
|
||||||
|
if ((!dma_line_bytes)
|
||||||
|
|| (dma_line_bytes % sizeof(uint64_t))
|
||||||
|
|| (dma_line_bytes > (OMV_LINE_BUF_SIZE / 2))
|
||||||
|
|| (!length)
|
||||||
|
|| (length % DMA_LENGTH_ALIGNMENT)) {
|
||||||
|
return SENSOR_ERROR_INVALID_FRAMESIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OMV_CSI_DMA)
|
||||||
|
// The code below will enable EDMA data transfer from the line buffer for non-JPEG modes.
|
||||||
|
if (sensor->pixformat != PIXFORMAT_JPEG) {
|
||||||
|
edma_config(sensor, bytes_per_pixel);
|
||||||
|
for (int i = 0; i < OMV_CSI_DMA_CHANNEL_COUNT; i++) {
|
||||||
|
EDMA_CreateHandle(&CSI_EDMA_Handle[i], OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL_START + i);
|
||||||
|
EDMA_DisableChannelInterrupts(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL_START + i, kEDMA_MajorInterruptEnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((sensor->pixformat == PIXFORMAT_RGB565 && sensor->hw_flags.rgb_swap)
|
if ((sensor->pixformat == PIXFORMAT_RGB565 && sensor->hw_flags.rgb_swap)
|
||||||
|| (sensor->pixformat == PIXFORMAT_YUV422 && sensor->hw_flags.yuv_swap)) {
|
|| (sensor->pixformat == PIXFORMAT_YUV422 && sensor->hw_flags.yuv_swap)) {
|
||||||
@ -353,7 +456,7 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) {
|
|||||||
// Wait for the DMA to finish the transfer.
|
// Wait for the DMA to finish the transfer.
|
||||||
for (mp_uint_t ticks = mp_hal_ticks_ms(); buffer == NULL;) {
|
for (mp_uint_t ticks = mp_hal_ticks_ms(); buffer == NULL;) {
|
||||||
MICROPY_EVENT_POLL_HOOK
|
MICROPY_EVENT_POLL_HOOK
|
||||||
if ((mp_hal_ticks_ms() - ticks) > 3000) {
|
if ((mp_hal_ticks_ms() - ticks) > SENSOR_TIMEOUT_MS) {
|
||||||
sensor_abort(true, false);
|
sensor_abort(true, false);
|
||||||
|
|
||||||
#if defined(OMV_CSI_FSYNC_PIN)
|
#if defined(OMV_CSI_FSYNC_PIN)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user