Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_dma.c
1 #include <bc_dma.h>
2 #include <bc_irq.h>
3 #include <bc_scheduler.h>
4 #include <bc_fifo.h>
5 #include <stm32l0xx.h>
6 
7 #define _BC_DMA_CHECK_IRQ_OF_CHANNEL_(__CHANNEL) \
8  if ((DMA1->ISR & DMA_ISR_GIF##__CHANNEL) != 0) \
9  { \
10  if ((DMA1->ISR & DMA_ISR_TEIF##__CHANNEL) != 0) \
11  { \
12  _bc_dma_irq_handler(BC_DMA_CHANNEL_##__CHANNEL, BC_DMA_EVENT_ERROR); \
13  } \
14  else if ((DMA1->ISR & DMA_ISR_HTIF##__CHANNEL) != 0) \
15  { \
16  _bc_dma_irq_handler(BC_DMA_CHANNEL_##__CHANNEL, BC_DMA_EVENT_HALF_DONE); \
17  DMA1->IFCR |= DMA_IFCR_CHTIF##__CHANNEL; \
18  } \
19  else if ((DMA1->ISR & DMA_ISR_TCIF##__CHANNEL) != 0) \
20  { \
21  _bc_dma_irq_handler(BC_DMA_CHANNEL_##__CHANNEL, BC_DMA_EVENT_DONE); \
22  DMA1->IFCR |= DMA_IFCR_CTCIF##__CHANNEL; \
23  } \
24  }
25 
26 typedef struct
27 {
28  uint8_t channel : 4;
29  uint8_t event : 4;
30 
32 
33 static bc_dma_pending_event_t _bc_dma_pending_event_buffer[2 * 7 * sizeof(bc_dma_pending_event_t)];
34 
35 static struct
36 {
37  bool is_initialized;
38 
39  struct
40  {
41  DMA_Channel_TypeDef *instance;
42  void (*event_handler)(bc_dma_channel_t, bc_dma_event_t, void *);
43  void *event_param;
44 
45  } channel[7];
46 
47  bc_fifo_t fifo_pending;
48  bc_scheduler_task_id_t task_id;
49 
50 } _bc_dma;
51 
52 static void _bc_dma_task(void *param);
53 
54 static void _bc_dma_irq_handler(bc_dma_channel_t channel, bc_dma_event_t event);
55 
56 void bc_dma_init(void)
57 {
58  if (_bc_dma.is_initialized)
59  {
60  return;
61  }
62 
63  // Initialize channel instances
64  _bc_dma.channel[BC_DMA_CHANNEL_1].instance = DMA1_Channel1;
65  _bc_dma.channel[BC_DMA_CHANNEL_2].instance = DMA1_Channel2;
66  _bc_dma.channel[BC_DMA_CHANNEL_3].instance = DMA1_Channel3;
67  _bc_dma.channel[BC_DMA_CHANNEL_4].instance = DMA1_Channel4;
68  _bc_dma.channel[BC_DMA_CHANNEL_5].instance = DMA1_Channel5;
69  _bc_dma.channel[BC_DMA_CHANNEL_6].instance = DMA1_Channel6;
70  _bc_dma.channel[BC_DMA_CHANNEL_7].instance = DMA1_Channel7;
71 
72  bc_fifo_init(&_bc_dma.fifo_pending, _bc_dma_pending_event_buffer, sizeof(_bc_dma_pending_event_buffer));
73 
74  _bc_dma.task_id = bc_scheduler_register(_bc_dma_task, NULL, BC_TICK_INFINITY);
75 
76  // Enable DMA1
77  RCC->AHBENR |= RCC_AHBENR_DMA1EN;
78 
79  // Errata workaround
80  RCC->AHBENR;
81 
82  // Enable DMA 1 channel 1 interrupt
83  NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
84  NVIC_EnableIRQ(DMA1_Channel1_IRQn);
85 
86  // Enable DMA 1 channel 2 and 3 interrupts
87  NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1);
88  NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
89 
90  // Enable DMA 1 channel 4, 5, 6 and 7 interrupts
91  NVIC_SetPriority(DMA1_Channel4_5_6_7_IRQn, 2);
92  NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn);
93 }
94 
96 {
97  DMA_Channel_TypeDef *dma_channel = _bc_dma.channel[channel].instance;
98 
99  uint32_t dma_cselr_pos = channel * 4;
100 
101  bc_irq_disable();
102 
103  // Set DMA direction
105  {
106  dma_channel->CCR |= DMA_CCR_DIR;
107  }
108  else
109  {
110  dma_channel->CCR &= ~DMA_CCR_DIR;
111  }
112 
113  // Set memory data size
114  dma_channel->CCR &= ~DMA_CCR_MSIZE_Msk;
115 
116  if (config->data_size_memory == BC_DMA_SIZE_2)
117  {
118  dma_channel->CCR |= DMA_CCR_MSIZE_0;
119  }
120  else if (config->data_size_memory == BC_DMA_SIZE_4)
121  {
122  dma_channel->CCR |= DMA_CCR_MSIZE_1;
123  }
124 
125  // Set peripheral data size
126  dma_channel->CCR &= ~DMA_CCR_PSIZE_Msk;
127 
128  if (config->data_size_peripheral == BC_DMA_SIZE_2)
129  {
130  dma_channel->CCR |= DMA_CCR_PSIZE_0;
131  }
132  else if (config->data_size_peripheral == BC_DMA_SIZE_4)
133  {
134  dma_channel->CCR |= DMA_CCR_PSIZE_1;
135  }
136 
137  // Set DMA mode
138  if (config->mode == BC_DMA_MODE_STANDARD)
139  {
140  dma_channel->CCR &= ~DMA_CCR_CIRC;
141  }
142  else if (config->mode == BC_DMA_MODE_CIRCULAR)
143  {
144  dma_channel->CCR |= DMA_CCR_CIRC;
145  }
146 
147  // Set memory incrementation
148  dma_channel->CCR |= DMA_CCR_MINC;
149 
150  // Set DMA channel priority
151  dma_channel->CCR &= ~DMA_CCR_PL_Msk;
152  dma_channel->CCR |= config->priority << DMA_CCR_PL_Pos;
153 
154  // Configure request selection for DMA1 Channel
155  DMA1_CSELR->CSELR &= ~(0xf << dma_cselr_pos);
156  DMA1_CSELR->CSELR |= config->request << dma_cselr_pos;
157 
158  // Configure DMA channel data length
159  dma_channel->CNDTR = config->length;
160 
161  // Configure DMA channel source address
162  dma_channel->CPAR = (uint32_t) config->address_peripheral;
163 
164  // Configure DMA channel destination address
165  dma_channel->CMAR = (uint32_t) config->address_memory;
166 
167  // Enable the transfer complete, half-complete and error interrupts
168  dma_channel->CCR |= DMA_CCR_TCIE | DMA_CCR_HTIE | DMA_CCR_TEIE;
169 
170  bc_irq_enable();
171 }
172 
173 void bc_dma_set_event_handler(bc_dma_channel_t channel, void (*event_handler)(bc_dma_channel_t, bc_dma_event_t, void *), void *event_param)
174 {
175  _bc_dma.channel[channel].event_handler = event_handler;
176  _bc_dma.channel[channel].event_param = event_param;
177 }
178 
180 {
181  _bc_dma.channel[channel].instance->CCR |= DMA_CCR_EN;
182 }
183 
185 {
186  _bc_dma.channel[channel].instance->CCR &= ~DMA_CCR_EN;
187 }
188 
189 size_t bc_dma_channel_get_length(bc_dma_channel_t channel)
190 {
191  return (size_t) _bc_dma.channel[channel].instance->CNDTR;
192 }
193 
194 void _bc_dma_task(void *param)
195 {
196  (void) param;
197 
198  bc_dma_pending_event_t pending_event;
199 
200  while (bc_fifo_read(&_bc_dma.fifo_pending, &pending_event, sizeof(bc_dma_pending_event_t)) != 0)
201  {
202  if (_bc_dma.channel[pending_event.channel].event_handler != NULL)
203  {
204  _bc_dma.channel[pending_event.channel].event_handler(pending_event.channel, pending_event.event, _bc_dma.channel[pending_event.channel].event_param);
205  }
206  }
207 }
208 
209 void _bc_dma_irq_handler(bc_dma_channel_t channel, bc_dma_event_t event)
210 {
211  if (event == BC_DMA_EVENT_DONE && !(_bc_dma.channel[channel].instance->CCR & DMA_CCR_CIRC))
212  {
213  bc_dma_channel_stop(channel);
214  }
215 
216  bc_dma_pending_event_t pending_event = { channel, event };
217 
218  bc_fifo_irq_write(&_bc_dma.fifo_pending, &pending_event, sizeof(bc_dma_pending_event_t));
219 
220  bc_scheduler_plan_now(_bc_dma.task_id);
221 }
222 
223 void DMA1_Channel1_IRQHandler(void)
224 {
225  _BC_DMA_CHECK_IRQ_OF_CHANNEL_(1);
226 }
227 
228 void DMA1_Channel2_3_IRQHandler(void)
229 {
230  _BC_DMA_CHECK_IRQ_OF_CHANNEL_(2);
231 
232  _BC_DMA_CHECK_IRQ_OF_CHANNEL_(3);
233 }
234 
235 void DMA1_Channel4_5_6_7_IRQHandler(void)
236 {
237  _BC_DMA_CHECK_IRQ_OF_CHANNEL_(4);
238 
239  _BC_DMA_CHECK_IRQ_OF_CHANNEL_(5);
240 
241  _BC_DMA_CHECK_IRQ_OF_CHANNEL_(6);
242 
243  _BC_DMA_CHECK_IRQ_OF_CHANNEL_(7);
244 }
size_t length
DMA channel data length.
Definition: bc_dma.h:180
DMA channel configuration.
Definition: bc_dma.h:165
DMA channel 1.
Definition: bc_dma.h:15
void bc_irq_enable(void)
Enable interrupt requests globally (call can be nested)
Definition: bc_irq.c:21
Structure of FIFO instance.
Definition: bc_fifo.h:12
DMA channel 4.
Definition: bc_dma.h:24
bc_dma_event_t
DMA channel event.
Definition: bc_dma.h:132
bc_dma_channel_t
DMA channels.
Definition: bc_dma.h:12
DMA channel data size 2B.
Definition: bc_dma.h:111
void * address_peripheral
Peripheral address.
Definition: bc_dma.h:189
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_scheduler_plan_now(bc_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
Definition: bc_scheduler.c:119
void bc_dma_set_event_handler(bc_dma_channel_t channel, void(*event_handler)(bc_dma_channel_t, bc_dma_event_t, void *), void *event_param)
Set callback function.
Definition: bc_dma.c:173
void * address_memory
RAM memory address.
Definition: bc_dma.h:186
DMA channel mode circular.
Definition: bc_dma.h:126
bc_dma_request_t request
DMA channel request.
Definition: bc_dma.h:168
bc_dma_direction_t direction
DMA channel direction.
Definition: bc_dma.h:171
void bc_dma_init(void)
Initialize DMA.
Definition: bc_dma.c:56
DMA channel 3.
Definition: bc_dma.h:21
void bc_dma_channel_run(bc_dma_channel_t channel)
Start DMA channel.
Definition: bc_dma.c:179
size_t bc_fifo_irq_write(bc_fifo_t *fifo, const void *buffer, size_t length)
Write data to FIFO from interrupt.
Definition: bc_fifo.c:101
DMA channel direction from RAM to peripheral.
Definition: bc_dma.h:96
DMA channel 7.
Definition: bc_dma.h:33
size_t bc_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: bc_scheduler.h:18
DMA channel 2.
Definition: bc_dma.h:18
void bc_fifo_init(bc_fifo_t *fifo, void *buffer, size_t size)
Initialize FIFO buffer.
Definition: bc_fifo.c:4
bc_dma_mode_t mode
DMA channel mode.
Definition: bc_dma.h:183
void bc_dma_channel_stop(bc_dma_channel_t channel)
Stop DMA channel.
Definition: bc_dma.c:184
bc_dma_priority_t priority
DMA channel priority.
Definition: bc_dma.h:192
DMA channel mode standard.
Definition: bc_dma.h:123
void bc_dma_channel_config(bc_dma_channel_t channel, bc_dma_channel_config_t *config)
Configure DMA channel.
Definition: bc_dma.c:95
bc_dma_size_t data_size_peripheral
DMA channel peripheral data size.
Definition: bc_dma.h:177
DMA channel data size 4B.
Definition: bc_dma.h:114
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
size_t bc_fifo_read(bc_fifo_t *fifo, void *buffer, size_t length)
Read data from FIFO.
Definition: bc_fifo.c:63
void bc_irq_disable(void)
Disable interrupt requests globally (call can be nested)
Definition: bc_irq.c:7
bc_dma_size_t data_size_memory
DMA channel memory data size.
Definition: bc_dma.h:174
DMA channel 6.
Definition: bc_dma.h:30
DMA channel 5, used for SPI.
Definition: bc_dma.h:27
DMA channel event done.
Definition: bc_dma.h:141