CommonPIC32

Annotated examples/demo/main.c

44:d00ca7551358
2018-10-23 Paul Boddie Experiment with interleaved DMA channels.
paul@15 1
/*
paul@15 2
 * A demonstration of various PIC32 peripherals.
paul@15 3
 *
paul@16 4
 * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
paul@15 5
 *
paul@15 6
 * This program is free software: you can redistribute it and/or modify
paul@15 7
 * it under the terms of the GNU General Public License as published by
paul@15 8
 * the Free Software Foundation, either version 3 of the License, or
paul@15 9
 * (at your option) any later version.
paul@15 10
 *
paul@15 11
 * This program is distributed in the hope that it will be useful,
paul@15 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@15 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@15 14
 * GNU General Public License for more details.
paul@15 15
 *
paul@15 16
 * You should have received a copy of the GNU General Public License
paul@15 17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
paul@15 18
 */
paul@15 19
paul@15 20
paul@0 21
#include "pic32_c.h"
paul@0 22
#include "init.h"
paul@11 23
#include "debug.h"
paul@16 24
#include "main.h"
paul@0 25
paul@13 26
static const char message1[] = "Hello!\r\n";
paul@44 27
paul@44 28
#define CELLSIZE4
paul@44 29
paul@44 30
#ifdef CELLSIZE1
paul@44 31
static const char message2[] = "Adoc gi,hlo\r";
paul@44 32
static const char message3[] = "n neaan el!\n";
paul@44 33
#define CELLSIZE 1
paul@44 34
#endif
paul@44 35
paul@44 36
#ifdef CELLSIZE4
paul@44 37
static const char message2[] = "And  agahell";
paul@44 38
static const char message3[] = "oncein, o!\r\n";
paul@44 39
#define CELLSIZE 4
paul@44 40
#endif
paul@44 41
paul@24 42
static int uart_echo;
paul@0 43
paul@15 44
paul@15 45
paul@16 46
/* Blink an attached LED with delays implemented using a loop. */
paul@16 47
paul@0 48
static void blink(uint32_t delay, uint32_t port, uint32_t pins)
paul@0 49
{
paul@0 50
    uint32_t counter;
paul@0 51
paul@0 52
    /* Clear outputs (LED). */
paul@0 53
paul@0 54
    CLR_REG(port, pins);
paul@0 55
paul@0 56
    while (1)
paul@0 57
    {
paul@0 58
        counter = delay;
paul@0 59
paul@0 60
        while (counter--) __asm__("");	/* retain loop */
paul@0 61
paul@0 62
        /* Invert outputs (LED). */
paul@0 63
paul@0 64
        INV_REG(port, pins);
paul@0 65
    }
paul@0 66
}
paul@0 67
paul@16 68
paul@16 69
paul@16 70
/* Main program. */
paul@16 71
paul@0 72
void main(void)
paul@0 73
{
paul@24 74
    uart_echo = 0;
paul@24 75
paul@0 76
    init_memory();
paul@0 77
    init_pins();
paul@0 78
    init_outputs();
paul@0 79
paul@0 80
    unlock_config();
paul@0 81
    config_uart();
paul@0 82
    lock_config();
paul@0 83
paul@11 84
    init_dma();
paul@3 85
paul@26 86
    /* Peripheral relationships:
paul@26 87
paul@44 88
       Timer3 -> OC1 -> DMA0: message2 -> U1TXREG
paul@44 89
                     ___/
paul@44 90
                    /
paul@44 91
       Timer2 -> DMA1: message1 -> U1TXREG
paul@26 92
                    \___
paul@26 93
                        \
paul@44 94
       Timer3 -> OC1 -> DMA2: message3 -> U1TXREG
paul@26 95
    */
paul@26 96
paul@44 97
    /* Enable DMA on the next channel's completion, with OC1 initiating
paul@44 98
       transfers, raising a transfer completion interrupt to be handled. */
paul@44 99
paul@44 100
    dma_init(0, 2);
paul@44 101
    dma_set_chaining(0, dma_chain_next);
paul@44 102
    dma_set_interrupt(0, OC1, 1);
paul@44 103
    dma_set_transfer(0, PHYSICAL((uint32_t) message2), sizeof(message2) - 1,
paul@44 104
                        HW_PHYSICAL(UART_REG(1, UxTXREG)), 1,
paul@44 105
                        CELLSIZE);
paul@44 106
paul@13 107
    /* Initiate DMA on the Timer2 interrupt. Since the channel is not
paul@20 108
       auto-enabled, it must be explicitly enabled elsewhere (when a UART
paul@20 109
       interrupt is handled). */
paul@11 110
paul@44 111
    dma_init(1, 3);
paul@44 112
    dma_set_interrupt(1, T2, 1);
paul@44 113
    dma_set_transfer(1, PHYSICAL((uint32_t) message1), sizeof(message1) - 1,
paul@13 114
                        HW_PHYSICAL(UART_REG(1, UxTXREG)), 1,
paul@13 115
                        1);
paul@13 116
paul@14 117
    /* Enable DMA on the preceding channel's completion, with OC1 initiating
paul@14 118
       transfers, raising a transfer completion interrupt to be handled. */
paul@13 119
paul@44 120
    dma_init(2, 2);
paul@44 121
    dma_set_chaining(2, dma_chain_previous);
paul@44 122
    dma_set_interrupt(2, OC1, 1);
paul@44 123
    dma_set_transfer(2, PHYSICAL((uint32_t) message3), sizeof(message3) - 1,
paul@3 124
                        HW_PHYSICAL(UART_REG(1, UxTXREG)), 1,
paul@44 125
                        CELLSIZE);
paul@44 126
    dma_init_interrupt(2, 0b00001000, 7, 3);
paul@13 127
paul@14 128
    /* Configure a timer for the first DMA channel whose interrupt condition
paul@26 129
       drives the transfer. The interrupt itself does not need to be enabled. */
paul@3 130
paul@13 131
    timer_init(2, 0b111, 60000);
paul@13 132
    timer_on(2);
paul@13 133
paul@14 134
    /* Configure a timer for the output compare unit below. */
paul@14 135
paul@14 136
    timer_init(3, 0b111, 20000);
paul@13 137
    timer_on(3);
paul@13 138
paul@14 139
    /* Configure output compare in dual compare (continuous output) mode using
paul@14 140
       Timer3 as time base. The interrupt condition drives the second DMA
paul@26 141
       channel but does not need to be enabled. */
paul@14 142
paul@14 143
    oc_init(1, 0b101, 3);
paul@14 144
    oc_set_pulse(1, 10000);
paul@14 145
    oc_set_pulse_end(1, 20000);
paul@14 146
    oc_on(1);
paul@14 147
paul@20 148
    /* Set UART interrupt priority above CPU priority to process events and to
paul@20 149
       enable the first DMA channel. */
paul@3 150
paul@3 151
    uart_init(1, 115200);
paul@13 152
    uart_init_interrupt(1, UxRIF, 7, 3);
paul@3 153
    uart_on(1);
paul@0 154
paul@0 155
    interrupts_on();
paul@0 156
paul@0 157
    blink(3 << 24, PORTA, 1 << 3);
paul@0 158
}
paul@0 159
paul@16 160
paul@16 161
paul@16 162
/* Exception and interrupt handlers. */
paul@16 163
paul@0 164
void exception_handler(void)
paul@0 165
{
paul@0 166
    blink(3 << 12, PORTA, 1 << 3);
paul@0 167
}
paul@0 168
paul@0 169
void interrupt_handler(void)
paul@0 170
{
paul@19 171
    uint32_t ifs;
paul@19 172
    char val;
paul@11 173
paul@3 174
    /* Check for a UART receive interrupt condition (UxRIF). */
paul@0 175
paul@11 176
    ifs = REG(UARTIFS) & UART_INT_FLAGS(1, UxRIF);
paul@8 177
paul@8 178
    if (ifs)
paul@3 179
    {
paul@8 180
        /* Clear the UART interrupt condition. */
paul@8 181
paul@8 182
        CLR_REG(UARTIFS, ifs);
paul@8 183
paul@3 184
        /* Write the received data back. */
paul@0 185
paul@19 186
        while (uart_can_read(1))
paul@11 187
        {
paul@19 188
            val = uart_read_char(1);
paul@11 189
            if (uart_echo)
paul@19 190
                uart_write_char(1, val);
paul@13 191
paul@13 192
            /* Initiate transfer upon receiving a particular character. */
paul@13 193
paul@13 194
            if (val == '0')
paul@44 195
                dma_on(1);
paul@11 196
        }
paul@11 197
    }
paul@18 198
paul@18 199
    /* Check for a DMA interrupt condition (CHBCIF). */
paul@18 200
paul@44 201
    ifs = REG(DMAIFS) & DMA_INT_FLAGS(2, DCHxIF);
paul@18 202
paul@18 203
    if (ifs)
paul@18 204
    {
paul@18 205
        uart_write_string("CHBCIF\r\n");
paul@18 206
        INV_REG(PORTA, 1 << 2);
paul@44 207
        CLR_REG(DMA_REG(2, DCHxINT), 0b11111111);
paul@18 208
        CLR_REG(DMAIFS, ifs);
paul@18 209
    }
paul@0 210
}
paul@16 211
paul@16 212
paul@16 213
paul@16 214
/* Peripheral pin configuration. */
paul@16 215
paul@16 216
void config_uart(void)
paul@16 217
{
paul@16 218
    /* Map U1RX to RPB13. */
paul@16 219
paul@16 220
    REG(U1RXR) = 0b0011;        /* U1RXR<3:0> = 0011 (RPB13) */
paul@16 221
paul@16 222
    /* Map U1TX to RPB15. */
paul@16 223
paul@16 224
    REG(RPB15R) = 0b0001;       /* RPB15R<3:0> = 0001 (U1TX) */
paul@16 225
paul@16 226
    /* Set RPB13 to input. */
paul@16 227
paul@16 228
    SET_REG(TRISB, 1 << 13);
paul@16 229
}