3333#include "py/obj.h"
3434#include "irq.h"
3535
36- #define NSTREAM (16)
36+ #define NSTREAMS_PER_CONTROLLER (8)
37+ #define NCONTROLLERS (2)
38+ #define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER)
3739
3840static const uint8_t dma_irqn [NSTREAM ] = {
3941 DMA1_Stream0_IRQn ,
@@ -72,7 +74,16 @@ const DMA_InitTypeDef dma_init_struct_spi_i2c = {
7274};
7375
7476static DMA_HandleTypeDef * dma_handle [NSTREAM ] = {NULL };
75- static uint32_t dma_last_channel [NSTREAM ];
77+ static uint8_t dma_last_channel [NSTREAM ];
78+ static volatile uint32_t dma_enable_mask = 0 ;
79+
80+ volatile dma_idle_count_t dma_idle ;
81+
82+ #define DMA1_ENABLE_MASK 0x00ff // Bits in dma_enable_mask corresponfing to DMA1
83+ #define DMA2_ENABLE_MASK 0xff00 // Bits in dma_enable_mask corresponding to DMA2
84+ #define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid
85+
86+ #define DMA_CHANNEL_AS_UINT8 (dma_channel ) (((dma_channel) & DMA_SxCR_CHSEL) >> 24)
7687
7788void DMA1_Stream0_IRQHandler (void ) { if (dma_handle [0 ] != NULL ) { HAL_DMA_IRQHandler (dma_handle [0 ]); } }
7889void DMA1_Stream1_IRQHandler (void ) { if (dma_handle [1 ] != NULL ) { HAL_DMA_IRQHandler (dma_handle [1 ]); } }
@@ -91,19 +102,76 @@ void DMA2_Stream5_IRQHandler(void) { if (dma_handle[13] != NULL) { HAL_DMA_IRQHa
91102void DMA2_Stream6_IRQHandler (void ) { if (dma_handle [14 ] != NULL ) { HAL_DMA_IRQHandler (dma_handle [14 ]); } }
92103void DMA2_Stream7_IRQHandler (void ) { if (dma_handle [15 ] != NULL ) { HAL_DMA_IRQHandler (dma_handle [15 ]); } }
93104
105+ #define DMA1_IS_CLK_ENABLED () ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0)
106+ #define DMA2_IS_CLK_ENABLED () ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0)
107+
94108static int get_dma_id (DMA_Stream_TypeDef * dma_stream ) {
95- if ((uint32_t )dma_stream < DMA2_BASE ) {
96- return ((uint32_t )dma_stream - DMA1_Stream0_BASE ) / 0x18 ;
109+ int dma_id ;
110+ if (dma_stream < DMA2_Stream0 ) {
111+ dma_id = dma_stream - DMA1_Stream0 ;
112+ } else {
113+ dma_id = NSTREAMS_PER_CONTROLLER + (dma_stream - DMA2_Stream0 );
114+ }
115+ return dma_id ;
116+ }
117+
118+ // Resets the idle counter for the DMA controller associated with dma_id.
119+ static void dma_tickle (int dma_id ) {
120+ if (dma_id < NSTREAMS_PER_CONTROLLER ) {
121+ dma_idle .counter [0 ] = 1 ;
122+ } else {
123+ dma_idle .counter [1 ] = 1 ;
124+ }
125+ }
126+
127+ static void dma_enable_clock (int dma_id ) {
128+ // We don't want dma_tick_handler() to turn off the clock right after we
129+ // enable it, so we need to mark the channel in use in an atomic fashion.
130+ mp_uint_t irq_state = MICROPY_BEGIN_ATOMIC_SECTION ();
131+ uint32_t old_enable_mask = dma_enable_mask ;
132+ dma_enable_mask |= (1 << dma_id );
133+ MICROPY_END_ATOMIC_SECTION (irq_state );
134+
135+ if (dma_id <= 7 ) {
136+ if (((old_enable_mask & DMA1_ENABLE_MASK ) == 0 ) && !DMA1_IS_CLK_ENABLED ()) {
137+ __DMA1_CLK_ENABLE ();
138+
139+ // We just turned on the clock. This means that anything stored
140+ // in dma_last_channel (for DMA1) needs to be invalidated.
141+
142+ for (int channel = 0 ; channel < NSTREAMS_PER_CONTROLLER ; channel ++ ) {
143+ dma_last_channel [channel ] = DMA_INVALID_CHANNEL ;
144+ }
145+ }
97146 } else {
98- return (NSTREAM / 2 ) + ((uint32_t )dma_stream - DMA2_Stream0_BASE ) / 0x18 ;
147+ if (((old_enable_mask & DMA2_ENABLE_MASK ) == 0 ) && !DMA2_IS_CLK_ENABLED ()) {
148+ __DMA2_CLK_ENABLE ();
149+
150+ // We just turned on the clock. This means that anything stored
151+ // in dma_last_channel (for DMA1) needs to be invalidated.
152+
153+ for (int channel = NSTREAMS_PER_CONTROLLER ; channel < NSTREAM ; channel ++ ) {
154+ dma_last_channel [channel ] = DMA_INVALID_CHANNEL ;
155+ }
156+ }
99157 }
100158}
101159
160+ static void dma_disable_clock (int dma_id ) {
161+ // We just mark the clock as disabled here, but we don't actually disable it.
162+ // We wait for the timer to expire first, which means that back-to-back
163+ // transfers don't have to initialize as much.
164+ dma_tickle (dma_id );
165+ dma_enable_mask &= ~(1 << dma_id );
166+ }
167+
102168void dma_init (DMA_HandleTypeDef * dma , DMA_Stream_TypeDef * dma_stream , const DMA_InitTypeDef * dma_init , uint32_t dma_channel , uint32_t direction , void * data ) {
103169 int dma_id = get_dma_id (dma_stream );
104170 //printf("dma_init(%p, %p(%d), 0x%x, 0x%x, %p)\n", dma, dma_stream, dma_id, (uint)dma_channel, (uint)direction, data);
105171
106- // TODO possibly don't need to clear the entire structure
172+ // Some drivers allocate the DMA_HandleTypeDef from the stack
173+ // (i.e. dac, i2c, spi) and for those cases we need to clear the
174+ // structure so we don't get random values from the stack)
107175 memset (dma , 0 , sizeof (* dma ));
108176
109177 // set global pointer for IRQ handler
@@ -119,22 +187,20 @@ void dma_init(DMA_HandleTypeDef *dma, DMA_Stream_TypeDef *dma_stream, const DMA_
119187 // caller must implement other half by doing: data->xxx = dma
120188 dma -> Parent = data ;
121189
190+ dma_enable_clock (dma_id );
191+
122192 // if this stream was previously configured for this channel then we
123193 // can skip most of the initialisation
124- if (dma_last_channel [dma_id ] == dma_channel ) {
194+ uint8_t channel_uint8 = DMA_CHANNEL_AS_UINT8 (dma_channel );
195+ if (dma_last_channel [dma_id ] == channel_uint8 ) {
125196 goto same_channel ;
126197 }
127- dma_last_channel [dma_id ] = dma_channel ;
128-
129- // enable clock for needed DMA peripheral
130- if (dma_id <= 7 ) {
131- __DMA1_CLK_ENABLE ();
132- } else {
133- __DMA2_CLK_ENABLE ();
134- }
198+ dma_last_channel [dma_id ] = channel_uint8 ;
135199
136200 // reset and configure DMA peripheral
137- HAL_DMA_DeInit (dma );
201+ if (HAL_DMA_GetState (dma ) != HAL_DMA_STATE_RESET ) {
202+ HAL_DMA_DeInit (dma );
203+ }
138204 HAL_DMA_Init (dma );
139205 HAL_NVIC_SetPriority (dma_irqn [dma_id ], IRQ_PRI_DMA , IRQ_SUBPRI_DMA );
140206
@@ -146,11 +212,41 @@ void dma_deinit(DMA_HandleTypeDef *dma) {
146212 int dma_id = get_dma_id (dma -> Instance );
147213 HAL_NVIC_DisableIRQ (dma_irqn [dma_id ]);
148214 dma_handle [dma_id ] = NULL ;
215+
216+ dma_disable_clock (dma_id );
149217}
150218
151219void dma_invalidate_channel (DMA_Stream_TypeDef * dma_stream , uint32_t dma_channel ) {
152220 int dma_id = get_dma_id (dma_stream );
153- if (dma_last_channel [dma_id ] == dma_channel ) {
154- dma_last_channel [dma_id ] = 0xffffffff ;
221+ if (dma_last_channel [dma_id ] == DMA_CHANNEL_AS_UINT8 (dma_channel )) {
222+ dma_last_channel [dma_id ] = DMA_INVALID_CHANNEL ;
223+ }
224+ }
225+
226+ // Called from the SysTick handler (once per millisecond)
227+ void dma_idle_handler () {
228+ static const uint32_t controller_mask [] = {
229+ DMA1_ENABLE_MASK , DMA2_ENABLE_MASK
230+ };
231+ for (int controller = 0 ; controller < NCONTROLLERS ; controller ++ ) {
232+ if (dma_idle .counter [controller ] == 0 ) {
233+ continue ;
234+ }
235+ if (++ dma_idle .counter [controller ] > DMA_IDLE_TICK_MAX ) {
236+ if ((dma_enable_mask & controller_mask [controller ]) == 0 ) {
237+ // Nothing is active and we've reached our idle timeout,
238+ // Now we'll really disable the clock.
239+ dma_idle .counter [controller ] = 0 ;
240+ if (controller == 0 ) {
241+ __DMA1_CLK_DISABLE ();
242+ } else {
243+ __DMA2_CLK_DISABLE ();
244+ }
245+ } else {
246+ // Something is still active, but the counter never got
247+ // reset, so we'll reset the counter here.
248+ dma_idle .counter [controller ] = 1 ;
249+ }
250+ }
155251 }
156252}
0 commit comments