mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
ports/stm32: Refactor MDMA code.
Moved to separate file to make omv_csi more readable. Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
This commit is contained in:
parent
85179136ab
commit
2b4d66ba23
@ -50,7 +50,6 @@
|
|||||||
|
|
||||||
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
#if defined(OMV_MDMA_CHANNEL_DCMI_0)
|
||||||
#define USE_MDMA (1)
|
#define USE_MDMA (1)
|
||||||
#define MDMA_BUFFER_SIZE (64)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(DCMIPP)
|
#if !defined(DCMIPP)
|
||||||
@ -590,22 +589,12 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
bytes_per_pixel = sizeof(uint8_t);
|
bytes_per_pixel = sizeof(uint8_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For all non-JPEG and non-transposed modes image capture can be completely offload to MDMA.
|
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
|
// For non-JPEG, non-transposed modes, offload the capture to MDMA.
|
||||||
|
// Note that MDMA is started here, not in FRAME/VSYNC callbacks, to
|
||||||
|
// maximize the time before the frame has to be dropped.
|
||||||
if (!csi->transpose) {
|
if (!csi->transpose) {
|
||||||
// NOTE: MDMA is started here, not in FRAME/VSYNC callbacks, to maximize the time before
|
stm_mdma_start(csi, (uint32_t) src, (uint32_t) dst, fb->u * bytes_per_pixel, fb->v);
|
||||||
// the frame has to be dropped.
|
|
||||||
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
|
||||||
// mdma0 will copy this line of the image to the final destination.
|
|
||||||
__HAL_UNLOCK(&csi->mdma0);
|
|
||||||
csi->mdma0.State = HAL_MDMA_STATE_READY;
|
|
||||||
HAL_MDMA_Start(&csi->mdma0, (uint32_t) src, (uint32_t) dst,
|
|
||||||
line_width_bytes, 1);
|
|
||||||
// mdma1 will copy all remaining lines of the image to the final destination.
|
|
||||||
__HAL_UNLOCK(&csi->mdma1);
|
|
||||||
csi->mdma1.State = HAL_MDMA_STATE_READY;
|
|
||||||
HAL_MDMA_Start(&csi->mdma1, (uint32_t) src, (uint32_t) (dst + line_width_bytes),
|
|
||||||
line_width_bytes, fb->v - 1);
|
|
||||||
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -618,7 +607,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
// Two MDMA channels are used to maximize the time available for each channel to finish the transfer.
|
// Two MDMA channels are used to maximize the time available to finish the transfer.
|
||||||
omv_csi_copy_line(csi, (buffer->offset % 2) ? &csi->mdma1 : &csi->mdma0, src, dst);
|
omv_csi_copy_line(csi, (buffer->offset % 2) ? &csi->mdma1 : &csi->mdma0, src, dst);
|
||||||
#else
|
#else
|
||||||
omv_csi_copy_line(csi, NULL, src, dst);
|
omv_csi_copy_line(csi, NULL, src, dst);
|
||||||
@ -626,125 +615,6 @@ void DCMI_DMAConvCpltUser(uint32_t addr) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if USE_MDMA
|
|
||||||
// Configures an MDMA channel to completely offload the CPU in copying one line of pixels.
|
|
||||||
static void omv_csi_mdma_config(omv_csi_t *csi, MDMA_InitTypeDef *init, uint32_t bytes_per_pixel) {
|
|
||||||
framebuffer_t *fb = csi->fb;
|
|
||||||
|
|
||||||
init->Request = MDMA_REQUEST_SW;
|
|
||||||
init->TransferTriggerMode = MDMA_REPEAT_BLOCK_TRANSFER;
|
|
||||||
init->Priority = MDMA_PRIORITY_VERY_HIGH;
|
|
||||||
init->DataAlignment = MDMA_DATAALIGN_PACKENABLE;
|
|
||||||
init->BufferTransferLength = MDMA_BUFFER_SIZE;
|
|
||||||
// The source address is 1KB aligned. So, a burst size of 16 beats (AHB Max) should not break.
|
|
||||||
// Destination lines may not be aligned however so the burst size must be computed.
|
|
||||||
init->SourceBurst = MDMA_SOURCE_BURST_16BEATS;
|
|
||||||
init->SourceBlockAddressOffset = 0;
|
|
||||||
init->DestBlockAddressOffset = 0;
|
|
||||||
|
|
||||||
if ((csi->pixformat == PIXFORMAT_RGB565 && csi->rgb_swap) ||
|
|
||||||
(csi->pixformat == PIXFORMAT_YUV422 && csi->yuv_swap)) {
|
|
||||||
init->Endianness = MDMA_LITTLE_BYTE_ENDIANNESS_EXCHANGE;
|
|
||||||
} else {
|
|
||||||
init->Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t line_offset_bytes = (fb->x * bytes_per_pixel) - get_dcmi_hw_crop(csi, bytes_per_pixel);
|
|
||||||
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
|
||||||
|
|
||||||
if (csi->transpose) {
|
|
||||||
line_width_bytes = bytes_per_pixel;
|
|
||||||
init->DestBlockAddressOffset = (fb->v - 1) * bytes_per_pixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// YUV422 Source -> Y Destination
|
|
||||||
if ((csi->pixformat == PIXFORMAT_GRAYSCALE) && (csi->mono_bpp == 2)) {
|
|
||||||
line_width_bytes /= 2;
|
|
||||||
if (csi->transpose) {
|
|
||||||
init->DestBlockAddressOffset /= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The destination will be 32-byte aligned, so the line width is broken into the largest
|
|
||||||
// power of 2. The source may have an offset, further limiting this to a sub power of 2.
|
|
||||||
for (int i = 3; i >= 0; i--) {
|
|
||||||
if (!(line_width_bytes % (1 << i))) {
|
|
||||||
for (int j = IM_MIN(i, 2); j >= 0; j--) {
|
|
||||||
if (!(line_offset_bytes % (1 << j))) {
|
|
||||||
init->SourceInc = MDMA_CTCR_SINC_1 | (j << MDMA_CTCR_SINCOS_Pos);
|
|
||||||
init->SourceDataSize = j << MDMA_CTCR_SSIZE_Pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init->DestinationInc = MDMA_CTCR_DINC_1 | (i << MDMA_CTCR_DINCOS_Pos);
|
|
||||||
init->DestDataSize = i << MDMA_CTCR_DSIZE_Pos;
|
|
||||||
|
|
||||||
// Find the burst size we can break the destination transfer up into.
|
|
||||||
uint32_t count = MDMA_BUFFER_SIZE >> i;
|
|
||||||
|
|
||||||
for (int i = 7; i >= 0; i--) {
|
|
||||||
if (!(count % (1 << i))) {
|
|
||||||
init->DestBurst = i << MDMA_CTCR_DBURST_Pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// YUV422 Source -> Y Destination
|
|
||||||
if ((csi->pixformat == PIXFORMAT_GRAYSCALE) && (csi->mono_bpp == 2)) {
|
|
||||||
init->SourceInc = MDMA_SRC_INC_HALFWORD;
|
|
||||||
init->SourceDataSize = MDMA_SRC_DATASIZE_BYTE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void omv_csi_mdma_enable(omv_csi_t *csi, uint32_t bytes_per_pixel) {
|
|
||||||
framebuffer_t *fb = csi->fb;
|
|
||||||
|
|
||||||
omv_csi_mdma_config(csi, &csi->mdma0.Init, bytes_per_pixel);
|
|
||||||
memcpy(&csi->mdma1.Init, &csi->mdma0.Init, sizeof(MDMA_InitTypeDef));
|
|
||||||
HAL_MDMA_Init(&csi->mdma0);
|
|
||||||
|
|
||||||
// If we are not transposing the image we can fully offload image capture from the CPU.
|
|
||||||
if (!csi->transpose) {
|
|
||||||
// MDMA will trigger on each TC from DMA and transfer one line to the frame buffer.
|
|
||||||
csi->mdma1.Init.Request = MDMA_REQUEST_DMA2_Stream1_TC;
|
|
||||||
csi->mdma1.Init.TransferTriggerMode = MDMA_BLOCK_TRANSFER;
|
|
||||||
// We setup MDMA to repeatedly reset itself to transfer the same line buffer.
|
|
||||||
csi->mdma1.Init.SourceBlockAddressOffset = -(fb->u * bytes_per_pixel);
|
|
||||||
}
|
|
||||||
|
|
||||||
HAL_MDMA_Init(&csi->mdma1);
|
|
||||||
if (!csi->transpose) {
|
|
||||||
HAL_MDMA_ConfigPostRequestMask(&csi->mdma1, (uint32_t) &DMA2->LIFCR, DMA_FLAG_TCIF1_5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int omv_csi_dma_memcpy(omv_csi_t *csi, void *dma, void *dst, void *src, int bpp, bool transposed) {
|
|
||||||
framebuffer_t *fb = csi->fb;
|
|
||||||
MDMA_HandleTypeDef *handle = dma;
|
|
||||||
|
|
||||||
// Drop the frame if MDMA is not keeping up as the image will be corrupted.
|
|
||||||
if (handle->Instance->CCR & MDMA_CCR_EN) {
|
|
||||||
csi->drop_frame = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If MDMA is still running, HAL_MDMA_Start() will start a new transfer.
|
|
||||||
__HAL_UNLOCK(handle);
|
|
||||||
handle->State = HAL_MDMA_STATE_READY;
|
|
||||||
HAL_MDMA_Start(handle,
|
|
||||||
(uint32_t) src,
|
|
||||||
(uint32_t) dst,
|
|
||||||
transposed ? bpp : (fb->u * bpp),
|
|
||||||
transposed ? fb->u : 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if USE_DCMIPP
|
#if USE_DCMIPP
|
||||||
void omv_csi_update_awb(omv_csi_t *csi, uint32_t n_pixels) {
|
void omv_csi_update_awb(omv_csi_t *csi, uint32_t n_pixels) {
|
||||||
uint32_t avg[3];
|
uint32_t avg[3];
|
||||||
@ -865,9 +735,11 @@ static int stm_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
// Enable MDMA transfer from the DCMI line buffer for non-JPEG modes.
|
// Configure MDMA for non-JPEG modes. MDMA will be used to either
|
||||||
|
// completely offload the transfer, in case of non-transposed mode
|
||||||
|
// or copy transposed lines.
|
||||||
if (csi->pixformat != PIXFORMAT_JPEG) {
|
if (csi->pixformat != PIXFORMAT_JPEG) {
|
||||||
omv_csi_mdma_enable(csi, bytes_per_pixel);
|
stm_mdma_init(csi, bytes_per_pixel, x_crop);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -889,10 +761,9 @@ static int stm_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
#if USE_MDMA
|
#if USE_MDMA
|
||||||
} else if ((csi->pixformat != PIXFORMAT_JPEG) && (!csi->transpose)) {
|
} else if ((csi->pixformat != PIXFORMAT_JPEG) && (!csi->transpose)) {
|
||||||
// Start an MDMA transfer, which completely offloads the capture to MDMA.
|
// Special transfer mode that uses DMA in circular mode and MDMA
|
||||||
// DMA to circular mode writing the same line over and over again.
|
// to move the lines to the final destination.
|
||||||
((DMA_Stream_TypeDef *) csi->dma.Instance)->CR |= DMA_SxCR_CIRC;
|
((DMA_Stream_TypeDef *) csi->dma.Instance)->CR |= DMA_SxCR_CIRC;
|
||||||
// DCMI will transfer to same line and MDMA will move to final location.
|
|
||||||
HAL_DCMI_Start_DMA(&csi->dcmi, DCMI_MODE_CONTINUOUS,
|
HAL_DCMI_Start_DMA(&csi->dcmi, DCMI_MODE_CONTINUOUS,
|
||||||
(uint32_t) &_line_buf, line_width_bytes / sizeof(uint32_t));
|
(uint32_t) &_line_buf, line_width_bytes / sizeof(uint32_t));
|
||||||
#endif // USE_MDMA
|
#endif // USE_MDMA
|
||||||
|
|||||||
@ -186,6 +186,140 @@ uint8_t stm_dma_mpu_region_size(uint32_t size) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef OMV_MDMA_CHANNEL_DCMI_0
|
||||||
|
void stm_mdma_init(omv_csi_t *csi, uint32_t bytes_per_pixel, uint32_t x_crop) {
|
||||||
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
|
stm_mdma_init_channel(csi, &csi->mdma0.Init, bytes_per_pixel, x_crop);
|
||||||
|
memcpy(&csi->mdma1.Init, &csi->mdma0.Init, sizeof(MDMA_InitTypeDef));
|
||||||
|
HAL_MDMA_Init(&csi->mdma0);
|
||||||
|
|
||||||
|
// If we are not transposing the image we can fully offload image capture from the CPU.
|
||||||
|
if (!csi->transpose) {
|
||||||
|
// MDMA will trigger on each TC from DMA and transfer one line to the frame buffer.
|
||||||
|
csi->mdma1.Init.Request = MDMA_REQUEST_DMA2_Stream1_TC;
|
||||||
|
csi->mdma1.Init.TransferTriggerMode = MDMA_BLOCK_TRANSFER;
|
||||||
|
// We setup MDMA to repeatedly reset itself to transfer the same line buffer.
|
||||||
|
csi->mdma1.Init.SourceBlockAddressOffset = -(fb->u * bytes_per_pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
HAL_MDMA_Init(&csi->mdma1);
|
||||||
|
if (!csi->transpose) {
|
||||||
|
HAL_MDMA_ConfigPostRequestMask(&csi->mdma1, (uint32_t) &DMA2->LIFCR, DMA_FLAG_TCIF1_5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configures an MDMA channel to completely offload the CPU in copying one line of pixels.
|
||||||
|
static void stm_mdma_init_channel(omv_csi_t *csi,
|
||||||
|
MDMA_InitTypeDef *init, uint32_t bytes_per_pixel, uint32_t x_crop) {
|
||||||
|
framebuffer_t *fb = csi->fb;
|
||||||
|
|
||||||
|
init->Request = MDMA_REQUEST_SW;
|
||||||
|
init->TransferTriggerMode = MDMA_REPEAT_BLOCK_TRANSFER;
|
||||||
|
init->Priority = MDMA_PRIORITY_VERY_HIGH;
|
||||||
|
init->DataAlignment = MDMA_DATAALIGN_PACKENABLE;
|
||||||
|
init->BufferTransferLength = MDMA_BUFFER_SIZE;
|
||||||
|
// The source address is 1KB aligned. So, a burst size of 16 beats
|
||||||
|
// (AHB Max) should not break. Destination lines may not be aligned
|
||||||
|
// however so the burst size must be computed.
|
||||||
|
init->SourceBurst = MDMA_SOURCE_BURST_16BEATS;
|
||||||
|
init->SourceBlockAddressOffset = 0;
|
||||||
|
init->DestBlockAddressOffset = 0;
|
||||||
|
|
||||||
|
if ((csi->pixformat == PIXFORMAT_RGB565 && csi->rgb_swap) ||
|
||||||
|
(csi->pixformat == PIXFORMAT_YUV422 && csi->yuv_swap)) {
|
||||||
|
init->Endianness = MDMA_LITTLE_BYTE_ENDIANNESS_EXCHANGE;
|
||||||
|
} else {
|
||||||
|
init->Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t line_offset_bytes = (fb->x * bytes_per_pixel) - x_crop;
|
||||||
|
uint32_t line_width_bytes = fb->u * bytes_per_pixel;
|
||||||
|
|
||||||
|
if (csi->transpose) {
|
||||||
|
line_width_bytes = bytes_per_pixel;
|
||||||
|
init->DestBlockAddressOffset = (fb->v - 1) * bytes_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// YUV422 Source -> Y Destination
|
||||||
|
if ((csi->pixformat == PIXFORMAT_GRAYSCALE) && (csi->mono_bpp == 2)) {
|
||||||
|
line_width_bytes /= 2;
|
||||||
|
if (csi->transpose) {
|
||||||
|
init->DestBlockAddressOffset /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The destination will be 32-byte aligned, so the line width is broken
|
||||||
|
// into the largest power of 2. The source may have an offset, further
|
||||||
|
// limiting this to a sub power of 2.
|
||||||
|
for (int i = 3; i >= 0; i--) {
|
||||||
|
if (!(line_width_bytes % (1 << i))) {
|
||||||
|
for (int j = IM_MIN(i, 2); j >= 0; j--) {
|
||||||
|
if (!(line_offset_bytes % (1 << j))) {
|
||||||
|
init->SourceInc = MDMA_CTCR_SINC_1 | (j << MDMA_CTCR_SINCOS_Pos);
|
||||||
|
init->SourceDataSize = j << MDMA_CTCR_SSIZE_Pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init->DestinationInc = MDMA_CTCR_DINC_1 | (i << MDMA_CTCR_DINCOS_Pos);
|
||||||
|
init->DestDataSize = i << MDMA_CTCR_DSIZE_Pos;
|
||||||
|
|
||||||
|
// Find the burst size we can break the destination transfer up into.
|
||||||
|
uint32_t count = MDMA_BUFFER_SIZE >> i;
|
||||||
|
|
||||||
|
for (int i = 7; i >= 0; i--) {
|
||||||
|
if (!(count % (1 << i))) {
|
||||||
|
init->DestBurst = i << MDMA_CTCR_DBURST_Pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// YUV422 Source -> Y Destination
|
||||||
|
if ((csi->pixformat == PIXFORMAT_GRAYSCALE) && (csi->mono_bpp == 2)) {
|
||||||
|
init->SourceInc = MDMA_SRC_INC_HALFWORD;
|
||||||
|
init->SourceDataSize = MDMA_SRC_DATASIZE_BYTE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stm_mdma_start(omv_csi_t *csi, uint32_t src, uint32_t dst, uint32_t line_width, uint32_t line_count) {
|
||||||
|
// mdma0 will copy this line of the image to the final destination.
|
||||||
|
__HAL_UNLOCK(&csi->mdma0);
|
||||||
|
csi->mdma0.State = HAL_MDMA_STATE_READY;
|
||||||
|
HAL_MDMA_Start(&csi->mdma0, src, dst, line_width, 1);
|
||||||
|
|
||||||
|
// mdma1 will copy all remaining lines of the image to the final destination.
|
||||||
|
__HAL_UNLOCK(&csi->mdma1);
|
||||||
|
csi->mdma1.State = HAL_MDMA_STATE_READY;
|
||||||
|
HAL_MDMA_Start(&csi->mdma1, src, dst + line_width, line_width, line_count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int omv_csi_dma_memcpy(omv_csi_t *csi, void *dma, void *dst, void *src, int bpp, bool transposed) {
|
||||||
|
framebuffer_t *fb = csi->fb;
|
||||||
|
MDMA_HandleTypeDef *handle = dma;
|
||||||
|
|
||||||
|
// Drop the frame if MDMA is not keeping up as the image will be corrupted.
|
||||||
|
if (handle->Instance->CCR & MDMA_CCR_EN) {
|
||||||
|
csi->drop_frame = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If MDMA is still running, HAL_MDMA_Start() will start a new transfer.
|
||||||
|
__HAL_UNLOCK(handle);
|
||||||
|
handle->State = HAL_MDMA_STATE_READY;
|
||||||
|
HAL_MDMA_Start(handle,
|
||||||
|
(uint32_t) src,
|
||||||
|
(uint32_t) dst,
|
||||||
|
transposed ? bpp : (fb->u * bpp),
|
||||||
|
transposed ? fb->u : 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // OMV_MDMA_CHANNEL_DCMI_0
|
||||||
|
|
||||||
#if defined(GPDMA1)
|
#if defined(GPDMA1)
|
||||||
static inline void stm_dma_irq_handler(size_t irqn) {
|
static inline void stm_dma_irq_handler(size_t irqn) {
|
||||||
if (dma_handle[irqn] != NULL) {
|
if (dma_handle[irqn] != NULL) {
|
||||||
|
|||||||
@ -29,4 +29,17 @@ uint8_t stm_dma_channel_to_irqn(void *dma_channel);
|
|||||||
uint8_t stm_dma_channel_to_id(void *dma_channel);
|
uint8_t stm_dma_channel_to_id(void *dma_channel);
|
||||||
int stm_dma_set_irq_descr(void *dma_channel, DMA_HandleTypeDef *dma_descr);
|
int stm_dma_set_irq_descr(void *dma_channel, DMA_HandleTypeDef *dma_descr);
|
||||||
uint8_t stm_dma_mpu_region_size(uint32_t size);
|
uint8_t stm_dma_mpu_region_size(uint32_t size);
|
||||||
|
|
||||||
|
#ifdef OMV_MDMA_CHANNEL_DCMI_0
|
||||||
|
#include "omv_csi.h"
|
||||||
|
|
||||||
|
#define MDMA_BUFFER_SIZE (64)
|
||||||
|
#define MDMA_CHAN_TO_INSTANCE(x) \
|
||||||
|
(MDMA_Channel_TypeDef *) (MDMA_Channel0_BASE + ((MDMA_Channel1_BASE - MDMA_Channel0_BASE) * x))
|
||||||
|
|
||||||
|
void stm_mdma_init(omv_csi_t *csi, uint32_t bytes_per_pixel, uint32_t x_crop);
|
||||||
|
void stm_mdma_init_channel(omv_csi_t *csi, MDMA_InitTypeDef *init, uint32_t bytes_per_pixel, uint32_t x_crop);
|
||||||
|
void stm_mdma_start(omv_csi_t *csi, uint32_t src, uint32_t dst, uint32_t line_width, uint32_t line_count);
|
||||||
|
#endif // OMV_MDMA_CHANNEL_DCMI_0
|
||||||
|
|
||||||
#endif // __STM_DMA_H__
|
#endif // __STM_DMA_H__
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user