Pico-Arduino
PicoDMA.h
1 #pragma once
2 #include "hardware/dma.h"
3 
4 namespace pico_arduino {
5 
11 template <class T>
12 class PicoDMA {
13  public:
15  PicoDMA(){}
16 
19  releaseChannel(true);
20  }
21 
23  bool releaseChannel(bool abortProcessing=false){
24  if (channel_no == -1) {
25  return true;
26  }
27  // if we are still processing - we might need to abort
28  if (isBusy()) {
29  if (abortProcessing){
30  abort();
31  } else {
32  return false;
33  }
34  }
35  dma_channel_unclaim(channel_no);
36  channel_no = -1;
37  return true;
38  }
39 
41  int channel() {
42  return channel_no;
43  }
44 
54  void copy(T* dst, T* src, int len, boolean start = true){
55  setupChannel();
56  // we dont use any interrupts in this method
57  irq_set_enabled(DMA_IRQ_0, true);
58 
59  // 8 bit transfers. Both read and write address increment after each
60  // transfer (each pointing to a location in src or dst respectively).
61  // No DREQ is selected, so the DMA transfers as fast as it can.
62  dma_channel_config c = dma_channel_get_default_config(channel_no);
63  channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
64  channel_config_set_read_increment(&c, true);
65  channel_config_set_write_increment(&c, true);
66  dma_channel_configure(
67  channel_no, // Channel to be configured
68  &c, // The configuration we just created
69  dst, // The initial write address
70  src, // The initial read address
71  len * sizeof(T) , // Number of transfers; in this case each is 1 byte.
72  start // Start immediately.
73  );
74  }
75 
85  void copy(T* dst, T* src, int len, void (*completion_handler)(), bool startCopy=true){
86  copy(dst, src, len, false);
87 
88  // Tell the DMA to raise IRQ line 0 when the channel finishes a block
89  dma_channel_set_irq0_enabled(channel_no, true);
90 
91  // Configure the processor to run dma_handler() when DMA IRQ 0 is asserted
92  irq_set_exclusive_handler(DMA_IRQ_0, completion_handler);
93  irq_set_enabled(DMA_IRQ_0, true);
94 
95  // starts the processing
96  if (startCopy) start(channel_no);
97  }
98 
99 
110  bool set(T* dst, T src, int len, boolean start = true){
111  if (sizeof(T)>4){
112  Logger.error("Only data up to 32 bytes is supported by DMA");
113  return false;
114  }
115  setupChannel();
116  T src_copy = src;
117 
118  // we dont use any interrupts in this method
119  irq_set_enabled(DMA_IRQ_0, true);
120 
121  // 8 bit transfers. Both read and write address increment after each
122  // transfer (each pointing to a location in src or dst respectively).
123  // No DREQ is selected, so the DMA transfers as fast as it can.
124  dma_channel_config c = dma_channel_get_default_config(channel_no);
125  channel_config_set_transfer_data_size(&c, transferSize());
126  channel_config_set_read_increment(&c, false);
127  channel_config_set_write_increment(&c, true);
128  dma_channel_configure(
129  channel_no, // Channel to be configured
130  &c, // The configuration we just created
131  dst, // The initial write address
132  &src_copy, // The initial read address
133  len, // Number of transfers; in this case each is 1 byte.
134  start // Start immediately.
135  );
136  return true;
137 
138  }
139 
148  void set(T* dst, T src, int len, void (*completion_handler)(), bool startCopy=true){
149  // set values
150  set(dst, src, len, false);
151 
152  // Tell the DMA to raise IRQ line 0 when the channel finishes a block
153  dma_channel_set_irq0_enabled(channel_no, true);
154 
155  // Configure the processor to run dma_handler() when DMA IRQ 0 is asserted
156  irq_set_exclusive_handler(DMA_IRQ_0, completion_handler);
157  irq_set_enabled(DMA_IRQ_0, true);
158 
159  // starts the processing
160  if (startCopy) start(channel_no);
161 ;
162  }
163 
165  void start(){
166  if (channel_no!=-1) dma_channel_start(channel_no);
167  }
168 
170  void abort(){
171  if (channel_no!=-1) dma_channel_abort(channel_no);
172  }
173 
175  void wait(){
176  if (channel_no!=-1) dma_channel_wait_for_finish_blocking(channel_no);
177  }
178 
180  bool isBusy(){
181  return channel_no==-1 ? true : dma_channel_is_busy(channel_no);
182  }
183 
185  void clearInterrupt() {
186  dma_hw->ints0 = 1u << channel;
187  //irq_clear(DMA_IRQ_0);
188  }
189 
190  protected:
191  int channel_no = -1;
192 
193  dma_channel_transfer_size transferSize() {
194  switch(sizeof(T)){
195  case 1:
196  return DMA_SIZE_8;
197  case 2:
198  return DMA_SIZE_16;
199  case 4:
200  return DMA_SIZE_32;
201  }
202  }
203 
205  void setupChannel() {
206  if (channel_no == -1){
207  channel_no = dma_claim_unused_channel(true);
208  }
209  }
210 
211 };
212 
213 }
We can use the Pico DMA to copy data "in the background" while the processor is doing some other work...
Definition: PicoDMA.h:12
PicoDMA()
Default constructor.
Definition: PicoDMA.h:15
bool set(T *dst, T src, int len, boolean start=true)
Sets a destination array with a fixed value We support only data of the size of uint_8,...
Definition: PicoDMA.h:110
int channel()
provides the used DMA channel - returns -1 if no channel has been set up so far
Definition: PicoDMA.h:41
bool isBusy()
checks if the copy is still in process
Definition: PicoDMA.h:180
void start()
starts the copy
Definition: PicoDMA.h:165
void copy(T *dst, T *src, int len, boolean start=true)
Copies the values of num bytes from the location pointed to by source directly to the memory block po...
Definition: PicoDMA.h:54
void copy(T *dst, T *src, int len, void(*completion_handler)(), bool startCopy=true)
Copies the values of num bytes from the location pointed to by source directly to the memory block po...
Definition: PicoDMA.h:85
void abort()
aborts the copy
Definition: PicoDMA.h:170
~PicoDMA()
Destructor: releases the DMA channel if necessary - if some processing is still going on,...
Definition: PicoDMA.h:18
bool releaseChannel(bool abortProcessing=false)
Releases the DMA channel and makes it available again.
Definition: PicoDMA.h:23
void set(T *dst, T src, int len, void(*completion_handler)(), bool startCopy=true)
Sets a destination array with a fixed value.
Definition: PicoDMA.h:148
void setupChannel()
Provides the next available DMA channel.
Definition: PicoDMA.h:205
void wait()
a blocking wait for the copy to complete
Definition: PicoDMA.h:175
void clearInterrupt()
You need to call this method in the completion handler.
Definition: PicoDMA.h:185
virtual void error(const char *str, const char *str1=nullptr, const char *str2=nullptr)
logs an error
Definition: PicoLogger.h:45
Pico Arduino Framework.
Definition: Arduino.cpp:26