mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
ports/stm32: Add DMA init functions.
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
This commit is contained in:
parent
cf0a58372d
commit
6406e719ce
@ -24,6 +24,8 @@
|
||||
* STM32 DMA helper functions.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include STM32_HAL_H
|
||||
#include "py/mphal.h"
|
||||
|
||||
@ -38,6 +40,86 @@ static DMA_HandleTypeDef *dma_handle[32];
|
||||
extern DMA_HandleTypeDef *dma_handle[16];
|
||||
#endif
|
||||
|
||||
const DMA_InitTypeDef stm_dma_csi_init = {
|
||||
#if defined(STM32N6)
|
||||
.BlkHWRequest = DMA_BREQ_SINGLE_BURST,
|
||||
.Priority = DMA_HIGH_PRIORITY,
|
||||
.SrcBurstLength = 1,
|
||||
// The maximum allowed AXI burst length 16 for HPDMA.
|
||||
// TODO: Should set dynamically for GPDMA or other buses.
|
||||
.DestBurstLength = 16,
|
||||
.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER,
|
||||
#elif defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
|
||||
.PeriphInc = DMA_PINC_DISABLE,
|
||||
.MemInc = DMA_MINC_ENABLE,
|
||||
.Priority = DMA_PRIORITY_HIGH,
|
||||
.FIFOMode = DMA_FIFOMODE_ENABLE,
|
||||
.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL,
|
||||
.MemBurst = DMA_MBURST_INC4,
|
||||
.PeriphBurst = DMA_PBURST_SINGLE,
|
||||
#else
|
||||
#error Unsupported MCU
|
||||
#endif
|
||||
};
|
||||
|
||||
const DMA_InitTypeDef stm_dma_spi_init = {
|
||||
#if defined(STM32N6)
|
||||
.BlkHWRequest = DMA_BREQ_SINGLE_BURST,
|
||||
.Priority = DMA_HIGH_PRIORITY,
|
||||
.SrcBurstLength = 1,
|
||||
.DestBurstLength = 1,
|
||||
.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER,
|
||||
#elif defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
|
||||
.PeriphInc = DMA_PINC_DISABLE,
|
||||
.MemInc = DMA_MINC_ENABLE,
|
||||
.Priority = DMA_PRIORITY_HIGH,
|
||||
// If the FIFO is disabled (DMA direct mode), the source and
|
||||
// destination transfer widths are equal and both are defined
|
||||
// by PSIZE (MSIZE is ignored).
|
||||
.FIFOMode = DMA_FIFOMODE_DISABLE,
|
||||
.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL,
|
||||
// Note MBURST and PBURST are ignored in direct mode.
|
||||
.MemBurst = DMA_MBURST_SINGLE,
|
||||
.PeriphBurst = DMA_PBURST_SINGLE,
|
||||
#else
|
||||
#error Unsupported MCU
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(OMV_SAI)
|
||||
const DMA_InitTypeDef stm_dma_sai_init = {
|
||||
.PeriphInc = DMA_PINC_DISABLE,
|
||||
.MemInc = DMA_MINC_ENABLE,
|
||||
.Priority = DMA_PRIORITY_HIGH,
|
||||
.FIFOMode = DMA_FIFOMODE_ENABLE,
|
||||
.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL,
|
||||
.MemBurst = DMA_MBURST_SINGLE,
|
||||
.PeriphBurst = DMA_PBURST_SINGLE,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(OMV_DFSDM)
|
||||
const DMA_InitTypeDef stm_dma_dfsdm_init = {
|
||||
.PeriphInc = DMA_PINC_DISABLE,
|
||||
.MemInc = DMA_MINC_ENABLE,
|
||||
.Priority = DMA_PRIORITY_HIGH,
|
||||
.FIFOMode = DMA_FIFOMODE_DISABLE, // Note: wasn't set
|
||||
.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL,
|
||||
.MemBurst = DMA_MBURST_SINGLE,
|
||||
.PeriphBurst = DMA_PBURST_SINGLE,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(OMV_MDF)
|
||||
const DMA_InitTypeDef stm_dma_mdf_init = {
|
||||
.BlkHWRequest = DMA_BREQ_SINGLE_BURST,
|
||||
.Priority = DMA_HIGH_PRIORITY,
|
||||
.SrcBurstLength = 1,
|
||||
.DestBurstLength = 1,
|
||||
.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER,
|
||||
};
|
||||
#endif
|
||||
|
||||
uint8_t stm_dma_channel_to_irqn(void *dma_channel) {
|
||||
if (0) {
|
||||
#if defined(DMA1_Stream0)
|
||||
@ -186,6 +268,165 @@ uint8_t stm_dma_mpu_region_size(uint32_t size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(HPDMA1_Channel0)
|
||||
static bool stm_dma_is_hp_channel(void *dma_channel) {
|
||||
return ((((uint32_t) dma_channel) & 0xFFFFF000) == HPDMA1_BASE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t stm_dma_width(uint32_t size, bool source) {
|
||||
#if defined(STM32N6)
|
||||
switch(size) {
|
||||
case 1: return (source) ? DMA_SRC_DATAWIDTH_BYTE : DMA_DEST_DATAWIDTH_BYTE;
|
||||
case 2: return (source) ? DMA_SRC_DATAWIDTH_HALFWORD : DMA_DEST_DATAWIDTH_HALFWORD;
|
||||
case 4: return (source) ? DMA_SRC_DATAWIDTH_WORD : DMA_DEST_DATAWIDTH_WORD;
|
||||
case 8: return (source) ? DMA_SRC_DATAWIDTH_DOUBLEWORD : DMA_DEST_DATAWIDTH_DOUBLEWORD;
|
||||
default: return -1;
|
||||
}
|
||||
#else
|
||||
switch(size) {
|
||||
case 1: return (source) ? DMA_PDATAALIGN_BYTE : DMA_MDATAALIGN_BYTE;
|
||||
case 2: return (source) ? DMA_PDATAALIGN_HALFWORD : DMA_MDATAALIGN_HALFWORD;
|
||||
case 4: return (source) ? DMA_PDATAALIGN_WORD : DMA_MDATAALIGN_WORD;
|
||||
default: return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int stm_dma_init(DMA_HandleTypeDef *dma_descr, void *dma_channel, uint32_t request,
|
||||
uint32_t direction, uint32_t ssize, uint32_t dsize, uint32_t ports,
|
||||
const DMA_InitTypeDef *init, bool circular) {
|
||||
bool dma_init_done = true;
|
||||
DMA_InitTypeDef *dma_init = &dma_descr->Init;
|
||||
|
||||
// Set channel
|
||||
dma_descr->Instance = dma_channel;
|
||||
|
||||
// Copy static init.
|
||||
memcpy(dma_init, init, sizeof(DMA_InitTypeDef));
|
||||
|
||||
// Set request
|
||||
#if defined(STM32H7) || defined(STM32N6)
|
||||
dma_init->Request = request;
|
||||
#else
|
||||
dma_init->Channel = request;
|
||||
#endif
|
||||
|
||||
// Set direction
|
||||
dma_init->Direction = direction;
|
||||
|
||||
// Set src/dest increment
|
||||
#if defined(STM32N6)
|
||||
if (direction == DMA_PERIPH_TO_MEMORY) {
|
||||
dma_init->SrcInc = DMA_SINC_FIXED;
|
||||
dma_init->DestInc = DMA_DINC_INCREMENTED;
|
||||
} else {
|
||||
dma_init->SrcInc = DMA_SINC_INCREMENTED;
|
||||
dma_init->DestInc = DMA_DINC_FIXED;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Configure src/dest size/alignment
|
||||
#if defined(STM32N6)
|
||||
dma_init->SrcDataWidth = stm_dma_width(ssize, true);
|
||||
dma_init->DestDataWidth = stm_dma_width(dsize, false);
|
||||
#else
|
||||
dma_init->PeriphDataAlignment = stm_dma_width(ssize, true);
|
||||
dma_init->MemDataAlignment = stm_dma_width(dsize, false);
|
||||
#endif
|
||||
|
||||
// Set mode.
|
||||
#if defined(STM32N6)
|
||||
dma_init->Mode = DMA_NORMAL;
|
||||
#else
|
||||
dma_init->Mode = circular ? DMA_CIRCULAR : DMA_NORMAL;
|
||||
#endif
|
||||
|
||||
// Set allocated ports.
|
||||
#if defined(STM32N6)
|
||||
dma_init->TransferAllocatedPort = ports;
|
||||
#endif
|
||||
|
||||
// F4, F7, H7 or N6 in non-circular mode.
|
||||
#if defined(STM32N6)
|
||||
dma_init_done = !circular;
|
||||
#endif
|
||||
|
||||
if (dma_init_done) {
|
||||
HAL_DMA_DeInit(dma_descr);
|
||||
if (HAL_DMA_Init(dma_descr) != HAL_OK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(STM32N6)
|
||||
int stm_dma_ll_init(DMA_HandleTypeDef *dma_descr, DMA_QListTypeDef *dma_queue,
|
||||
DMA_NodeTypeDef *dma_nodes, size_t nodes_count, uint32_t ports) {
|
||||
bool is_hp = stm_dma_is_hp_channel(dma_descr->Instance);
|
||||
|
||||
DMA_NodeConfTypeDef node_conf = {
|
||||
.SrcSecure = DMA_CHANNEL_SRC_SEC,
|
||||
.DestSecure = DMA_CHANNEL_DEST_SEC,
|
||||
.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE,
|
||||
.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED,
|
||||
.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED,
|
||||
.NodeType = is_hp ? DMA_HPDMA_LINEAR_NODE : DMA_GPDMA_LINEAR_NODE,
|
||||
};
|
||||
|
||||
// Copy Node DMA init.
|
||||
memcpy(&node_conf.Init, &dma_descr->Init, sizeof(DMA_InitTypeDef));
|
||||
|
||||
// Clear DMA queue and node(s).
|
||||
memset(dma_queue, 0, sizeof(DMA_QListTypeDef));
|
||||
memset(dma_nodes, 0, sizeof(DMA_NodeTypeDef) * nodes_count);
|
||||
|
||||
DMA_NodeTypeDef *prev_node = NULL;
|
||||
for (size_t i=0; i<nodes_count; i++) {
|
||||
if (HAL_DMAEx_List_BuildNode(&node_conf, &dma_nodes[i]) != HAL_OK ||
|
||||
HAL_DMAEx_List_InsertNode(dma_queue, prev_node, &dma_nodes[i]) != HAL_OK) {
|
||||
return -1;
|
||||
}
|
||||
prev_node = &dma_nodes[i];
|
||||
}
|
||||
|
||||
if (HAL_DMAEx_List_SetCircularMode(dma_queue) != HAL_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dma_descr->InitLinkedList.Priority = DMA_HIGH_PRIORITY;
|
||||
dma_descr->InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
|
||||
dma_descr->InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
|
||||
dma_descr->InitLinkedList.LinkAllocatedPort = ports;
|
||||
dma_descr->InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
|
||||
|
||||
if (HAL_DMAEx_List_Init(dma_descr) != HAL_OK ||
|
||||
HAL_DMAEx_List_LinkQ(dma_descr, dma_queue) != HAL_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t chan_flags = DMA_CHANNEL_PRIV | DMA_CHANNEL_SEC |
|
||||
DMA_CHANNEL_SRC_SEC | DMA_CHANNEL_DEST_SEC;
|
||||
if (HAL_DMA_ConfigChannelAttributes(dma_descr, chan_flags) != HAL_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_hp) {
|
||||
DMA_IsolationConfigTypeDef isocfg = {
|
||||
.CidFiltering = DMA_ISOLATION_ON,
|
||||
.StaticCid = DMA_CHANNEL_STATIC_CID_1,
|
||||
};
|
||||
if (HAL_DMA_SetIsolationAttributes(dma_descr, &isocfg) != HAL_OK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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;
|
||||
@ -210,8 +451,7 @@ void stm_mdma_init(omv_csi_t *csi, uint32_t bytes_per_pixel, uint32_t x_crop) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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;
|
||||
@ -390,7 +630,9 @@ void GPDMA1_Channel14_IRQHandler(void) {
|
||||
void GPDMA1_Channel15_IRQHandler(void) {
|
||||
stm_dma_irq_handler(15);
|
||||
}
|
||||
#endif // GPDMA1
|
||||
|
||||
#if defined(HPDMA1)
|
||||
void HPDMA1_Channel0_IRQHandler(void) {
|
||||
stm_dma_irq_handler(16);
|
||||
}
|
||||
|
||||
@ -25,10 +25,28 @@
|
||||
*/
|
||||
#ifndef __STM_DMA_H__
|
||||
#define __STM_DMA_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include STM32_HAL_H
|
||||
|
||||
extern const DMA_InitTypeDef stm_dma_csi_init;
|
||||
extern const DMA_InitTypeDef stm_dma_spi_init;
|
||||
extern const DMA_InitTypeDef stm_dma_sai_init;
|
||||
extern const DMA_InitTypeDef stm_dma_dfsdm_init;
|
||||
extern const DMA_InitTypeDef stm_dma_mdf_init;
|
||||
|
||||
uint8_t stm_dma_channel_to_irqn(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);
|
||||
uint8_t stm_dma_mpu_region_size(uint32_t size);
|
||||
int stm_dma_init(DMA_HandleTypeDef *dma_descr, void *dma_channel, uint32_t request,
|
||||
uint32_t direction, uint32_t ssize, uint32_t dsize, uint32_t ports,
|
||||
const DMA_InitTypeDef *init, bool circular);
|
||||
|
||||
#if defined(STM32N6)
|
||||
int stm_dma_ll_init(DMA_HandleTypeDef *dma_descr, DMA_QListTypeDef *dma_queue,
|
||||
DMA_NodeTypeDef *dma_nodes, size_t nodes_count, uint32_t ports);
|
||||
#endif
|
||||
|
||||
#ifdef OMV_MDMA_CHANNEL_DCMI_0
|
||||
#include "omv_csi.h"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user