Answering my own question. Did an experiment. It is no issue, at all, to let BDMA write to GPIOx->MODER, as Memory to Pheriperal. By Chaining that DMA through an event a bidirectional interface can be created. The MODER write adds about 30ns to the actual DMA that I wanted. OUTPUT_OD still is not working for me for some reason, but would equate to the same code below as I would still need to write a 1 to all pins that need to switch to input.
Here is some example code, that triggers 2 different DMA operations from EXTI0, which are chained through an event with the DMAMuxer.
int InitializeDmaChannels(void)
{
HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams = {0};
__HAL_RCC_BDMA_CLK_ENABLE();
// Setup the MODE switching DMA that should execute before the other channels start.
{
DMA_Handle_Channel2.Instance = BDMA_Channel2;
DMA_Handle_Channel2.Init.Request = BDMA_REQUEST_GENERATOR0;
DMA_Handle_Channel2.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMA_Handle_Channel2.Init.PeriphInc = DMA_PINC_DISABLE;
DMA_Handle_Channel2.Init.MemInc = DMA_MINC_DISABLE;
DMA_Handle_Channel2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
DMA_Handle_Channel2.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
DMA_Handle_Channel2.Init.Mode = DMA_CIRCULAR;
DMA_Handle_Channel2.Init.Priority = DMA_PRIORITY_VERY_HIGH;
DMA_Handle_Channel2.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
DMA_Handle_Channel2.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
DMA_Handle_Channel2.Init.MemBurst = DMA_MBURST_SINGLE;
DMA_Handle_Channel2.Init.PeriphBurst = DMA_PBURST_SINGLE;
// Initialize the DMA for Transmission.
HAL_StatusTypeDef dmares = HAL_OK;
dmares = HAL_DMA_Init(&DMA_Handle_Channel2);
// Select Callbacks functions called after Transfer complete and Transfer error.
dmares = HAL_DMA_RegisterCallback(&DMA_Handle_Channel2, HAL_DMA_XFER_CPLT_CB_ID, NULL);
dmares = HAL_DMA_RegisterCallback(&DMA_Handle_Channel2, HAL_DMA_XFER_ERROR_CB_ID, HAL_TransferError);
// NVIC configuration for DMA transfer complete interrupt.
HAL_NVIC_SetPriority(BDMA_Channel2_IRQn, 1, 0);
HAL_NVIC_DisableIRQ(BDMA_Channel2_IRQn);
// Configure and enable the DMAMUX Request generator.
dmamux_ReqGenParams.SignalID = HAL_DMAMUX2_REQ_GEN_EXTI0;
dmamux_ReqGenParams.Polarity = HAL_DMAMUX_REQ_GEN_RISING_FALLING;
dmamux_ReqGenParams.RequestNumber = 1;
dmares = HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handle_Channel2, &dmamux_ReqGenParams);
HAL_DMA_MuxSyncConfigTypeDef Sync;
Sync.SyncSignalID = HAL_DMAMUX2_SYNC_EXTI0;
Sync.SyncPolarity = HAL_DMAMUX_SYNC_NO_EVENT;
Sync.SyncEnable = FunctionalState::DISABLE;
Sync.EventEnable = FunctionalState::ENABLE;
Sync.RequestNumber = 1;
dmares = HAL_DMAEx_ConfigMuxSync(&DMA_Handle_Channel2, &Sync);
// NVIC configuration for DMAMUX request generator overrun errors
HAL_NVIC_SetPriority(DMAMUX2_OVR_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMAMUX2_OVR_IRQn);
dmares = HAL_DMAEx_EnableMuxRequestGenerator(&DMA_Handle_Channel2);
dmares = HAL_DMA_Start_IT(&DMA_Handle_Channel2, (uint32_t)&(MODERDMA[1]), (uint32_t)&(GPIOB->MODER), 1);
}
MODERDMA[0] = 0xABFF0000;
MODERDMA[1] = 0x0CF000BB;
SCB_CleanDCache_by_Addr(MODERDMA, 8);
// Setup the Address capture DMA.
{
DMA_Handle_Channel0.Instance = BDMA_Channel0;
DMA_Handle_Channel0.Init.Request = BDMA_REQUEST_GENERATOR1;
DMA_Handle_Channel0.Init.Direction = DMA_PERIPH_TO_MEMORY;
DMA_Handle_Channel0.Init.PeriphInc = DMA_PINC_DISABLE;
DMA_Handle_Channel0.Init.MemInc = DMA_MINC_ENABLE;
DMA_Handle_Channel0.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
DMA_Handle_Channel0.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
DMA_Handle_Channel0.Init.Mode = DMA_CIRCULAR;
DMA_Handle_Channel0.Init.Priority = DMA_PRIORITY_HIGH;
DMA_Handle_Channel0.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
DMA_Handle_Channel0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
DMA_Handle_Channel0.Init.MemBurst = DMA_MBURST_SINGLE;
DMA_Handle_Channel0.Init.PeriphBurst = DMA_PBURST_SINGLE;
// Initialize the DMA for Transmission
HAL_StatusTypeDef dmares = HAL_OK;
dmares = HAL_DMA_Init(&DMA_Handle_Channel0);
// Select Callbacks functions called after Transfer complete and Transfer error.
dmares = HAL_DMA_RegisterCallback(&DMA_Handle_Channel0, HAL_DMA_XFER_CPLT_CB_ID, NULL);
dmares = HAL_DMA_RegisterCallback(&DMA_Handle_Channel0, HAL_DMA_XFER_ERROR_CB_ID, HAL_TransferError);
// NVIC configuration for DMA transfer complete interrupt.
HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);
// Configure and enable the DMAMUX Request generator.
dmamux_ReqGenParams.SignalID = HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH2_EVT;
dmamux_ReqGenParams.Polarity = HAL_DMAMUX_REQ_GEN_RISING;
dmamux_ReqGenParams.RequestNumber = 1;
dmares = HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handle_Channel0, &dmamux_ReqGenParams);
// NVIC configuration for DMAMUX request generator overrun errors
HAL_NVIC_SetPriority(DMAMUX2_OVR_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMAMUX2_OVR_IRQn);
dmares = HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handle_Channel0);
dmares = HAL_DMA_Start_IT(&DMA_Handle_Channel0, (uint32_t)&(GPIOB->IDR), (uint32_t)(PortBBuffer), 2);
}
return 0;
}