1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/examples/demo/main.c Sat Oct 20 19:24:34 2018 +0200
1.3 @@ -0,0 +1,197 @@
1.4 +/*
1.5 + * A demonstration of various PIC32 peripherals.
1.6 + *
1.7 + * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software: you can redistribute it and/or modify
1.10 + * it under the terms of the GNU General Public License as published by
1.11 + * the Free Software Foundation, either version 3 of the License, or
1.12 + * (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.21 + */
1.22 +
1.23 +
1.24 +#include "pic32_c.h"
1.25 +#include "init.h"
1.26 +#include "debug.h"
1.27 +#include "main.h"
1.28 +
1.29 +static const char message1[] = "Hello!\r\n";
1.30 +static const char message2[] = "Again!\r\n";
1.31 +static int uart_echo;
1.32 +
1.33 +
1.34 +
1.35 +/* Blink an attached LED with delays implemented using a loop. */
1.36 +
1.37 +static void blink(uint32_t delay, uint32_t port, uint32_t pins)
1.38 +{
1.39 + uint32_t counter;
1.40 +
1.41 + /* Clear outputs (LED). */
1.42 +
1.43 + CLR_REG(port, pins);
1.44 +
1.45 + while (1)
1.46 + {
1.47 + counter = delay;
1.48 +
1.49 + while (counter--) __asm__(""); /* retain loop */
1.50 +
1.51 + /* Invert outputs (LED). */
1.52 +
1.53 + INV_REG(port, pins);
1.54 + }
1.55 +}
1.56 +
1.57 +
1.58 +
1.59 +/* Main program. */
1.60 +
1.61 +void main(void)
1.62 +{
1.63 + uart_echo = 0;
1.64 +
1.65 + init_memory();
1.66 + init_pins();
1.67 + init_outputs();
1.68 +
1.69 + unlock_config();
1.70 + config_uart();
1.71 + lock_config();
1.72 +
1.73 + init_dma();
1.74 +
1.75 + /* Initiate DMA on the Timer2 interrupt. Since the channel is not
1.76 + auto-enabled, it must be explicitly enabled elsewhere (when a UART
1.77 + interrupt is handled). */
1.78 +
1.79 + dma_init(0, 3);
1.80 + dma_set_interrupt(0, T2, 1);
1.81 + dma_set_transfer(0, PHYSICAL((uint32_t) message1), sizeof(message1) - 1,
1.82 + HW_PHYSICAL(UART_REG(1, UxTXREG)), 1,
1.83 + 1);
1.84 +
1.85 + /* Enable DMA on the preceding channel's completion, with OC1 initiating
1.86 + transfers, raising a transfer completion interrupt to be handled. */
1.87 +
1.88 + dma_init(1, 3);
1.89 + dma_set_chaining(1, dma_chain_previous);
1.90 + dma_set_interrupt(1, OC1, 1);
1.91 + dma_set_transfer(1, PHYSICAL((uint32_t) message2), sizeof(message2) - 1,
1.92 + HW_PHYSICAL(UART_REG(1, UxTXREG)), 1,
1.93 + 1);
1.94 + dma_init_interrupt(1, 0b00001000, 7, 3);
1.95 +
1.96 + /* Configure a timer for the first DMA channel whose interrupt condition
1.97 + drives the transfer but is not handled (having a lower priority than the
1.98 + CPU. */
1.99 +
1.100 + timer_init(2, 0b111, 60000);
1.101 + timer_init_interrupt(2, 1, 3);
1.102 + timer_on(2);
1.103 +
1.104 + /* Configure a timer for the output compare unit below. */
1.105 +
1.106 + timer_init(3, 0b111, 20000);
1.107 + timer_on(3);
1.108 +
1.109 + /* Configure output compare in dual compare (continuous output) mode using
1.110 + Timer3 as time base. The interrupt condition drives the second DMA
1.111 + channel but is not handled (having a lower priority than the CPU). */
1.112 +
1.113 + oc_init(1, 0b101, 3);
1.114 + oc_set_pulse(1, 10000);
1.115 + oc_set_pulse_end(1, 20000);
1.116 + oc_init_interrupt(1, 1, 3);
1.117 + oc_on(1);
1.118 +
1.119 + /* Set UART interrupt priority above CPU priority to process events and to
1.120 + enable the first DMA channel. */
1.121 +
1.122 + uart_init(1, 115200);
1.123 + uart_init_interrupt(1, UxRIF, 7, 3);
1.124 + uart_on(1);
1.125 +
1.126 + interrupts_on();
1.127 +
1.128 + blink(3 << 24, PORTA, 1 << 3);
1.129 +}
1.130 +
1.131 +
1.132 +
1.133 +/* Exception and interrupt handlers. */
1.134 +
1.135 +void exception_handler(void)
1.136 +{
1.137 + blink(3 << 12, PORTA, 1 << 3);
1.138 +}
1.139 +
1.140 +void interrupt_handler(void)
1.141 +{
1.142 + uint32_t ifs;
1.143 + char val;
1.144 +
1.145 + /* Check for a UART receive interrupt condition (UxRIF). */
1.146 +
1.147 + ifs = REG(UARTIFS) & UART_INT_FLAGS(1, UxRIF);
1.148 +
1.149 + if (ifs)
1.150 + {
1.151 + /* Clear the UART interrupt condition. */
1.152 +
1.153 + CLR_REG(UARTIFS, ifs);
1.154 +
1.155 + /* Write the received data back. */
1.156 +
1.157 + while (uart_can_read(1))
1.158 + {
1.159 + val = uart_read_char(1);
1.160 + if (uart_echo)
1.161 + uart_write_char(1, val);
1.162 +
1.163 + /* Initiate transfer upon receiving a particular character. */
1.164 +
1.165 + if (val == '0')
1.166 + dma_on(0);
1.167 + }
1.168 + }
1.169 +
1.170 + /* Check for a DMA interrupt condition (CHBCIF). */
1.171 +
1.172 + ifs = REG(DMAIFS) & DMA_INT_FLAGS(1, DCHxIF);
1.173 +
1.174 + if (ifs)
1.175 + {
1.176 + uart_write_string("CHBCIF\r\n");
1.177 + INV_REG(PORTA, 1 << 2);
1.178 + CLR_REG(DMA_REG(1, DCHxINT), 0b11111111);
1.179 + CLR_REG(DMAIFS, ifs);
1.180 + }
1.181 +}
1.182 +
1.183 +
1.184 +
1.185 +/* Peripheral pin configuration. */
1.186 +
1.187 +void config_uart(void)
1.188 +{
1.189 + /* Map U1RX to RPB13. */
1.190 +
1.191 + REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */
1.192 +
1.193 + /* Map U1TX to RPB15. */
1.194 +
1.195 + REG(RPB15R) = 0b0001; /* RPB15R<3:0> = 0001 (U1TX) */
1.196 +
1.197 + /* Set RPB13 to input. */
1.198 +
1.199 + SET_REG(TRISB, 1 << 13);
1.200 +}