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