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