Using DMA to re-configure peripherals (STM32G474) - Page 1
Forum section: electronics / general

author: uer166
author_rank: Super Contributor
timestamp: February 18, 2022, 06:53:45 am
content: On STM32G4 I'm trying to figure out a way to trigger a memory-to-SFR transfer to e.g. re-configure a GPIO as output, or alternate (change GPIO->AFR).Never used DMA for anything before, I'm a little confused. The way I see it is it can be accomplished 2 ways:Use TIM1_CH1 to generate a DMA request, but instead of updating CCR1 from memory, the destination memory is setup such that it updates another peripheral's SFR.Use a (?somehow?) always-requested DMA transfer from memory to a SFR, but use the sync function to gate it to the rising edge of TIM1_CH1The reference manual is nebulous regarding interconnects, use, HAL only seems to deal with boilerplate set-ups. Is this possible at all in principle?

author: wek
author_rank: Frequent Contributor
timestamp: February 18, 2022, 07:32:27 am
content: 1., i.e. Use a timer update triggered DMA (i.e. TIMx_DIER.UDE=1 and the appropriate signal TIMx_UP selected in DMAMUX), and as you've said, set the SFR address into DMA_CPARx.> The reference manual is nebulous regarding interconnectsWhat exactly do you want to know?JW

author: uer166
author_rank: Super Contributor
timestamp: February 18, 2022, 07:56:56 am
content: Quote from: wek on February 18, 2022, 07:32:27 amBut I want the transfer to happen at a very specific time, at one of the PWM events set by CCR1/2/3.. registers. Would that work the same?I think I mostly would like to see either a HAL or direct register example using e.g. TIM1_CH3 as a trigger, to transfer a configuration word from SRAM to another peripheral. Not quite clear on the difference between a "DMAMUX trigger input", and "multiplexer input to resources", doesn't help that the reference manual is missing the peripheral block diagram.

author: wek
author_rank: Frequent Contributor
timestamp: February 18, 2022, 08:33:38 am
content: > I want the transfer to happen at a very specific time, at one of the PWM events set by CCR1/2/3.. registersIf you set TIMx_DIER.CCxDE, instead of TIMx_DIER.UDE, that will be the source of trigger to DMA, i.e. DMA will be triggered at the same time as the compare match (which is probably what you call "PWM event") for given timer channel happens.> I think I mostly would like to see either a HAL or direct register example using e.g. TIM1_CH3 as a trigger, to transfer a configuration word from SRAM to another peripheral.> Not quite clear on the difference between a "DMAMUX trigger input", and "multiplexer input to resources"Can't find "multiplexer input to resources" in RM0444 by textual search. Ah I see you omitted the "s" in "inputs". It's important to be precise.In the simplest form of DMAMUX usage - and you don't need anything else here - after you have enabled given trigger in its source peripheral - say for TIM1_CH3 it's setting TIM1_DIER.CC3DE, and of course setting up CH3 for Output Compare so that it generates the Compare match events, plus running the timer itself - you simply look up your trigger source in theDMAMUX: assignment of multiplexer inputs to resourcestable, and look at the number to the left of it - say for TIM1_CH3 it's 63. You then choose an arbitrary DMA channel - say DMA1 channel 3 - and look above the table, where is a narrative from which it follows that DMA1 channel 3 is triggered from DMAMUX channel 2 (yes the numbering is confusing, but in case of G4 it is at least correctly described in the current RM). You then write the trigger's number - i.e. 63 - into that DMAMUX channel's DMAMUX_CxCR.DMAREQ_ID. That's all.JW

author: uer166
author_rank: Super Contributor
timestamp: February 19, 2022, 03:13:08 am
content: Cool stuff, with above I was able to DMA into the BSRR register a sequence of 2 words using the CCR1 compare match as the trigger. I also output the CCR1 PWM, and it seems there is ~39.3ns latency while everything runs at 170MHz. I've had a bunch of jitter at fist, presumably due to bus contention, but I forgot to disable systick interrupt which incremented a variable in SRAM that DMA was contending with.What I don't get is, 39.3ns is 6.68 clock cycles: how can that be a fractional number when everything runs synchronous inside MCU. Both pins are set to "Very High Speed" so delays due to slew rate shouldn't be a problem.Next up: re-configuring the pin as an opamp I/O <-> GPIO repeatedly at high speed without CPU intervention.

author: uer166
author_rank: Super Contributor
timestamp: February 19, 2022, 07:31:26 am
content: I've gotten to the point where the DMA can set and reset the OPAMPINTEN bit to autonomously triggered by CCR1 match, and output an analog voltage, or a GPIO level (see scope shot, blue is opamp output that puts out VCC/4 on pin). But I realized I actually need multiple registers set based on compare match. One of them is a GPIO config register and potentially a BSRR.I've written minimal code to use chained DMA, and the goal is to have TIM1_CH1 trigger DMA1_CH1 which has event output enabled, which triggers DMA1_CH3 using the DMA_GENERATOR0.It is my understanding that one can use the event output from the first DMA transaction, trigger another unrelated DMA transaction. It seems that the first, "master" DMA transaction triggers fine, but the DMA_GENERATOR0 does not. I've attached some Cube configuration screenshots and this is the code:Code:int main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_LPUART1_UART_Init();MX_TIM1_Init();MX_DAC3_Init();MX_OPAMP3_Init();/* USER CODE BEGIN 2 */uint32_t data[] = {0, 100, 200, 400, 500, 600, 700, 800, 900, 1000};HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);// First word is CSR register with opamp connected to output pin, second is disconnecteduint32_t w[] = {0x139000ED, 0x139001ED};/* Enable the TIM Capture/Compare 1 DMA request */htim1.Instance->DIER |= TIM_DMA_CC1;// This DMA transaction works fineif(HAL_DMA_Start(&hdma_tim1_ch1, (uint32_t)&(w), (uint32_t)&(hopamp3.Instance->CSR), 2) != HAL_OK){// bkpt}// This does not workuint32_t x[] = {0x00000001, 0x00010000};if(HAL_DMA_Start(&hdma_dma_generator0, (uint32_t)&(x), (uint32_t)&GPIOA->BSRR, 2) != HAL_OK){// bkpt}HAL_DAC_Start(&hdac3, DAC_CHANNEL_2);HAL_DAC_SetValue(&hdac3, DAC_CHANNEL_2, DAC_ALIGN_12B_R, 1024);HAL_SuspendTick(); // To remove CPU->SRAM bus accessesGPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_1;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* This sets the GPIO output high whenever opamp is disconnected */GPIOB->BSRR |= (uint32_t)0x2;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while(1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */}Maybe this is a little too much for first-time DMA usage.. I'm honestly still not certain what the terminology between a DMA request, DMA channel, DMA trigger, DMA generator, and request number is, and how they interact.