aboutsummaryrefslogtreecommitdiffstats
path: root/examples/test-usart-dma.cpp
blob: 8fbcccb6a5c7e41e8c49ea7007afd8069a4f2d7e (plain)
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
116
117
118
119
120
121
122
123
/**
 * @file test-usart-dma.cpp
 * @author Marti Bolivar <mbolivar@leaflabs.com>
 *
 * Simple test of DMA used with a USART receiver.
 *
 * Configures a USART receiver for use with DMA.  Received bytes are
 * placed into a buffer, with an interrupt firing when the buffer is
 * full.  At that point, the USART transmitter will print the contents
 * of the byte buffer.  The buffer is continually filled and refilled
 * in this manner.
 *
 * This example isn't very robust; don't use it in production.  In
 * particular, since the buffer keeps filling (DMA_CIRC_MODE is set),
 * if you keep typing after filling the buffer, you'll overwrite
 * earlier bytes; this may happen before those earlier bytes are done
 * printing.
 *
 * This code is released into the public domain.
 */

#include <libmaple/dma.h>
#include <libmaple/usart.h>
#include <libmaple/gpio.h>

#include <wirish/wirish.h>

#define BAUD 9600

#define USART USART2
#define USART_HWSER Serial2
#define USART_DMA_DEV DMA1
#define USART_RX_DMA_CHANNEL DMA_CH6
#define USART_TX BOARD_USART2_TX_PIN
#define USART_RX BOARD_USART2_RX_PIN

#define BUF_SIZE 8
uint8 rx_buf[BUF_SIZE];

dma_irq_cause irq_cause;

volatile uint32 irq_fired = 0;

void init_usart(void);
void init_dma_xfer(void);
void rx_dma_irq(void);

void setup(void) {
    pinMode(BOARD_LED_PIN, OUTPUT);

    init_dma_xfer();
    init_usart();
}

void loop(void) {
    toggleLED();
    delay(100);

    dma_channel_reg_map *ch_regs = dma_channel_regs(USART_DMA_DEV,
                                                    USART_RX_DMA_CHANNEL);
    if (irq_fired) {
        USART_HWSER.println("** IRQ **");
        irq_fired = 0;
    }
    USART_HWSER.print("[");
    USART_HWSER.print(millis());
    USART_HWSER.print("]\tISR bits: 0x");
    uint8 isr_bits = dma_get_isr_bits(USART_DMA_DEV, USART_RX_DMA_CHANNEL);
    USART_HWSER.print(isr_bits, HEX);
    USART_HWSER.print("\tCCR: 0x");
    USART_HWSER.print(ch_regs->CCR, HEX);
    USART_HWSER.print("\tCNDTR: 0x");
    USART_HWSER.print(ch_regs->CNDTR, HEX);
    USART_HWSER.print("\tBuffer contents: ");
     for (int i = 0; i < BUF_SIZE; i++) {
        USART_HWSER.print('\'');
        USART_HWSER.print(rx_buf[i]);
        USART_HWSER.print('\'');
        if (i < BUF_SIZE - 1) USART_HWSER.print(", ");
    }
    USART_HWSER.println();
    if (isr_bits == 0x7) {
        USART_HWSER.println("** Clearing ISR bits.");
        dma_clear_isr_bits(USART_DMA_DEV, USART_RX_DMA_CHANNEL);
    }
}

/* Configure USART receiver for use with DMA */
void init_usart(void) {
    USART_HWSER.begin(BAUD);
    USART->regs->CR3 = USART_CR3_DMAR;
}

/* Configure DMA transmission */
void init_dma_xfer(void) {
    dma_init(USART_DMA_DEV);
    dma_setup_transfer(USART_DMA_DEV, USART_RX_DMA_CHANNEL,
                       &USART->regs->DR, DMA_SIZE_8BITS,
                       rx_buf,           DMA_SIZE_8BITS,
                       (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_TRNS_CMPLT));
    dma_set_num_transfers(USART_DMA_DEV, USART_RX_DMA_CHANNEL, BUF_SIZE);
    dma_attach_interrupt(USART_DMA_DEV, USART_RX_DMA_CHANNEL, rx_dma_irq);
    dma_enable(USART_DMA_DEV, USART_RX_DMA_CHANNEL);
}

void rx_dma_irq(void) {
    irq_fired = true;
}

// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated objects that need libmaple may fail.
__attribute__((constructor)) void premain() {
    init();
}

int main(void) {
    setup();

    while (true) {
        loop();
    }
    return 0;
}