Clock stop issue: STM32F4 DMA to RGB LED sign - Page 1
Forum section: electronics / general

author: Psi
author_rank: Super Contributor
timestamp: January 01, 2017, 11:13:40 am
content: Hi.I'm driving a 96x32 RGB LED display using the STM32F4 DMA controller to copy bytes from an array to PORTB every time TIM1 fires an update event.TIM1 also has a output compare match enabled which generates a data clock for the LED display to sync its reading of PORTB data.All of this is working fine except that the clock is so fast the DMA transfer complete interrupt handler is too slow to stop the timer after the correct number of clocks.And these extra clocks are causing issues.So i'm trying to figure out the best way to limit the number of clocks to a fixed value in hardware. eg, after x clocks the timer automatically stops itself somehow. (maybe using a second timer master/gated mode etc..)Does anyone with more experience with STM32F4 know the best way to get an exact number of output pulses from a timer?(Note that this is output pulses from the compare match that are driving the DMA transfer, not the actual timer ticks)Any help apprenticed.

author: mubes
author_rank: Regular Contributor
timestamp: January 01, 2017, 01:32:45 pm
content: You can gate one timer with a second one to get an exact number of iterations, something like this (cut and pasted from a CNC project);Code:void _startClock(uint32_t speedMin, uint32_t speedMax, uint32_t count)// Running at speed 'speed', provide 'count' pulses// 'speed' is in pulses/second (Hz)// Do not exceed 329411 pulses/sec as that divides by zero and never comes back.{// TICKTIMER runs as the master clock, gated by GATETIMERTICKTIMER->PSC = 0;TICKTIMER->ARR = (TIM1CLK/MOVESCALEFACTOR)/speedMin;TICKTIMER->CR2 = TIM_CR2_MMS_1; // Enable master modeTICKTIMER->SMCR=TIM_SMCR_SMS_0|TIM_SMCR_SMS_2; // Slave mode, gated by ITR0 (TIM1) inputsTICKTIMER->EGR = TIM_EGR_UG; // Force updateTICKTIMER->SR = 0; // Clear the update flagTICKTIMER->CR1 = TIM_CR1_ARPE|TIM_CR1_CEN; // Enable counter// Timer 1 gates TIMER2 then counts the pulses it creates,// un-gates it when ARR value is reachedGATETIMER->PSC=0;GATETIMER->ARR=(count*MOVESCALEFACTOR)+(MOVESCALEFACTOR>>1);GATETIMER->DIER = 0;GATETIMER->CCR1=2; // While count is greater than or equal to this TIM2 will be enabledGATETIMER->SMCR=TIM_SMCR_TS_0|TIM_SMCR_SMS; // Timer ticked by ITR1 (TIM2), external clock modeGATETIMER->CCMR1 = TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_2|TIM_CCMR1_OC1M_0;GATETIMER->CR2 = TIM_CR2_MMS_2; // Enable master mode - this is used to gate TIM2GATETIMER->EGR = TIM_EGR_UG; // Update registersGATETIMER->CNT=2; // Set count to ensure that CCR goes true (so TIM2 can run)GATETIMER->SR=0; // Clear update flagGATETIMER->DIER = TIM_DIER_UIE; // Enable interrupt on updateGATETIMER->CR1 |= TIM_CR1_OPM|TIM_CR1_CEN;NVIC_EnableIRQ(GATETIMER_IRQn);}DAVE

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: January 01, 2017, 02:21:36 pm
content: I had a similar issue doing DMA from a PIC32 to implement multiple SPI ports, which I guess is pretty much what you're doing.What I did was instead of using the DMA complete event to trigger an interrupt, it triggers a DMA on a second channel to DMA a constant into the timer control register to stop the timer.More here :

author: Psi
author_rank: Super Contributor
timestamp: January 01, 2017, 10:04:30 pm
content: Perfect Mike! Thanks,It's exactly what i want to do.Thanks mubes, will keep that code handy as it will be useful for other projects when i need to gate a timer.

author: Psi
author_rank: Super Contributor
timestamp: January 01, 2017, 11:10:46 pm
content: Hm.. it looks like the DMA events are not included in trigger inputs to DMA channel/streams on STM32F4.So a DMA complete event cannot trigger another DMA transfer in hardware. (Unless im missing something)I wonder if i could expand on your idea of using an unused pin on the port to switch off the clock as part of the data. But instead of an external logic gate i use DMA triggered from external interrupt on this pin and copy the disable bit to the timer register that way. EDIT: no, can't trigger DMA from GPIO change.Probably best idea is to sync up another timer with the DMA timer and trigger the stop DMA from a compare match on this timer.

author: Jeroen3
author_rank: Super Contributor
timestamp: January 02, 2017, 08:22:08 am
content: Put TIM_A in SMCR->SMS:Gated Modeby TRGO of TIM_B in CR2->MMS:Enableand single-shot downcounting mode using ARR.TIM_A will create the output clock, while also feeding the bit DMA request.The Update Event (underflow) of TIM_B can be used as DMA request to feed a new byte.What will happen is on start of TIM_B, also TIM_A is started. These are synced, if initialized correctly, TIM_A does 8 full cycles, while TIM_B does 1. Note that TIM_A might require a reset each byte (EGR: UG).You only need to solve the puzzle that solves the interconnects:TIM_B TRGO->TIM_ATIM_A_CC or TRGO->DMA_BITTIM_B_CC->DMA_BYTEYou can then use another timer to start TIM_B. But that is up to you.I've done 8x Synced SPI using SGPIO on LPC43xx parts. Might be a better part for your job.

author: Psi
author_rank: Super Contributor
timestamp: January 02, 2017, 11:49:55 am
content: thanksNeeds more testing but i seems to be working good now.The way i have it setup is..TIM1 does DMA transfer and outputs data clock using TIM1 OC1.TIM1 OC1 is also used as the TIM8 clock input (TIM1 master TIM8 slave)TIM8 then has its OC1 set to 192 which triggers a DMA that copies 0 into TIM1-CR1 control reg to stop it after exactly 192 clocks.

author: Jeroen3
author_rank: Super Contributor
timestamp: January 02, 2017, 03:07:00 pm
content: It's a bit odd, but that should work. Are you using bitbanding yet?