Select one of the symbols to view example projects that use it.
 
Outline
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
#include "hardware/structs/uart.h"
word0
word1
word2
word3
word4
word5
control_blocks
main()
Files
loading...
SourceVuRaspberry Pi Pico SDK and Examplescontrol_blocks samplecontrol_blocks.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/** * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause *//* ... */ // Use two DMA channels to make a programmed sequence of data transfers to the // UART (a data gather operation). One channel is responsible for transferring // the actual data, the other repeatedly reprograms that channel. #include <stdio.h> #include "pico/stdlib.h" #include "hardware/dma.h" #include "hardware/structs/uart.h" // These buffers will be DMA'd to the UART, one after the other. const char word0[] = "Transferring "; const char word1[] = "one "; const char word2[] = "word "; const char word3[] = "at "; const char word4[] = "a "; const char word5[] = "time.\n"; // Note the order of the fields here: it's important that the length is before // the read address, because the control channel is going to write to the last // two registers in alias 3 on the data channel: // +0x0 +0x4 +0x8 +0xC (Trigger) // Alias 0: READ_ADDR WRITE_ADDR TRANS_COUNT CTRL // Alias 1: CTRL READ_ADDR WRITE_ADDR TRANS_COUNT // Alias 2: CTRL TRANS_COUNT READ_ADDR WRITE_ADDR // Alias 3: CTRL WRITE_ADDR TRANS_COUNT READ_ADDR // // This will program the transfer count and read address of the data channel, // and trigger it. Once the data channel completes, it will restart the // control channel (via CHAIN_TO) to load the next two words into its control // registers. const struct {uint32_t len; const char *data;} control_blocks[] = { {count_of(word0) - 1, word0}, // Skip null terminator {count_of(word1) - 1, word1}, {count_of(word2) - 1, word2}, {count_of(word3) - 1, word3}, {count_of(word4) - 1, word4}, {count_of(word5) - 1, word5}, {0, NULL} // Null trigger to end chain. ...}; int main() { #ifndef uart_default #warning dma/control_blocks example requires a UART #else stdio_init_all(); puts("DMA control block example:"); // ctrl_chan loads control blocks into data_chan, which executes them. int ctrl_chan = dma_claim_unused_channel(true); int data_chan = dma_claim_unused_channel(true); // The control channel transfers two words into the data channel's control // registers, then halts. The write address wraps on a two-word // (eight-byte) boundary, so that the control channel writes the same two // registers when it is next triggered. dma_channel_config c = dma_channel_get_default_config(ctrl_chan); channel_config_set_transfer_data_size(&c, DMA_SIZE_32); channel_config_set_read_increment(&c, true); channel_config_set_write_increment(&c, true); channel_config_set_ring(&c, true, 3); // 1 << 3 byte boundary on write ptr dma_channel_configure( ctrl_chan, &c, &dma_hw->ch[data_chan].al3_transfer_count, // Initial write address &control_blocks[0], // Initial read address 2, // Halt after each control block false // Don't start yet ); // The data channel is set up to write to the UART FIFO (paced by the // UART's TX data request signal) and then chain to the control channel // once it completes. The control channel programs a new read address and // data length, and retriggers the data channel. c = dma_channel_get_default_config(data_chan); channel_config_set_transfer_data_size(&c, DMA_SIZE_8); channel_config_set_dreq(&c, uart_get_dreq(uart_default, true)); // Trigger ctrl_chan when data_chan completes channel_config_set_chain_to(&c, ctrl_chan); // Raise the IRQ flag when 0 is written to a trigger register (end of chain): channel_config_set_irq_quiet(&c, true); dma_channel_configure( data_chan, &c, &uart_get_hw(uart_default)->dr, NULL, // Initial read address and transfer count are unimportant; 0, // the control channel will reprogram them each time. false // Don't start yet. ); // Everything is ready to go. Tell the control channel to load the first // control block. Everything is automatic from here. dma_start_channel_mask(1u << ctrl_chan); // The data channel will assert its IRQ flag when it gets a null trigger, // indicating the end of the control block list. We're just going to wait // for the IRQ flag instead of setting up an interrupt handler. while (!(dma_hw->intr & 1u << data_chan)) tight_loop_contents(); dma_hw->ints0 = 1u << data_chan; puts("DMA finished.");/* ... */ #endif }{ ... }
Details