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 = 1; 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 init_memory(); 79 init_pins(); 80 init_outputs(); 81 82 unlock_config(); 83 config_uart(); 84 lock_config(); 85 86 init_dma(); 87 88 /* Peripheral relationships: 89 90 Timer3 -> OC1 -> DMA0: message2 -> U1TXREG 91 ___/ 92 / 93 Timer2 -> DMA1: message1 -> U1TXREG 94 \___ 95 \ 96 Timer3 -> OC1 -> DMA2: message3 -> U1TXREG 97 */ 98 99 /* Enable DMA on the next channel's completion, with OC1 initiating 100 transfers, raising a transfer completion interrupt to be handled. */ 101 102 dma_init(0, 2); 103 dma_set_chaining(0, dma_chain_next); 104 dma_set_interrupt(0, OC1, 1); 105 dma_set_transfer(0, PHYSICAL((uint32_t) message2), sizeof(message2) - 1, 106 HW_PHYSICAL(UART_REG(1, UxTXREG)), 1, 107 CELLSIZE); 108 109 /* Initiate DMA on the Timer2 interrupt. Since the channel is not 110 auto-enabled, it must be explicitly enabled elsewhere (when a UART 111 interrupt is handled). */ 112 113 dma_init(1, 3); 114 dma_set_interrupt(1, T2, 1); 115 dma_set_transfer(1, PHYSICAL((uint32_t) message1), sizeof(message1) - 1, 116 HW_PHYSICAL(UART_REG(1, UxTXREG)), 1, 117 1); 118 119 /* Enable DMA on the preceding channel's completion, with OC1 initiating 120 transfers, raising a transfer completion interrupt to be handled. */ 121 122 dma_init(2, 2); 123 dma_set_chaining(2, dma_chain_previous); 124 dma_set_interrupt(2, OC1, 1); 125 dma_set_transfer(2, PHYSICAL((uint32_t) message3), sizeof(message3) - 1, 126 HW_PHYSICAL(UART_REG(1, UxTXREG)), 1, 127 CELLSIZE); 128 dma_init_interrupt(2, 0b00001000, 7, 3); 129 130 /* Configure a timer for the first DMA channel whose interrupt condition 131 drives the transfer. The interrupt itself does not need to be enabled. */ 132 133 timer_init(2, 0b111, 60000); 134 timer_on(2); 135 136 /* Configure a timer for the output compare unit below. */ 137 138 timer_init(3, 0b111, 20000); 139 timer_on(3); 140 141 /* Configure output compare in dual compare (continuous output) mode using 142 Timer3 as time base. The interrupt condition drives the second DMA 143 channel but does not need to be enabled. */ 144 145 oc_init(1, 0b101, 3); 146 oc_set_pulse(1, 10000); 147 oc_set_pulse_end(1, 20000); 148 oc_on(1); 149 150 /* Set UART interrupt priority above CPU priority to process events and to 151 enable the first DMA channel. */ 152 153 uart_init(1, FPB, 115200); 154 uart_init_interrupt(1, UxRIF, 7, 3); 155 uart_on(1); 156 157 interrupts_on(); 158 159 blink(3 << 24, PORTA, 1 << 3); 160 } 161 162 163 164 /* Exception and interrupt handlers. */ 165 166 void exception_handler(void) 167 { 168 blink(3 << 12, PORTA, 1 << 3); 169 } 170 171 void interrupt_handler(void) 172 { 173 uint32_t ifs; 174 char val; 175 176 /* Check for a UART receive interrupt condition (UxRIF). */ 177 178 ifs = REG(UARTIFS) & UART_INT_FLAGS(1, UxRIF); 179 180 if (ifs) 181 { 182 /* Clear the UART interrupt condition. */ 183 184 CLR_REG(UARTIFS, ifs); 185 186 /* Write the received data back. */ 187 188 while (uart_can_read(1)) 189 { 190 val = uart_read_char(1); 191 if (uart_echo) 192 uart_write_char(1, val); 193 194 /* Initiate transfer upon receiving a particular character. */ 195 196 if (val == '0') 197 dma_on(1); 198 } 199 } 200 201 /* Check for a DMA interrupt condition (CHBCIF). */ 202 203 ifs = REG(DMAIFS) & DMA_INT_FLAGS(2, DCHxIF); 204 205 if (ifs) 206 { 207 uart_write_string("CHBCIF\r\n"); 208 INV_REG(PORTA, 1 << 2); 209 CLR_REG(DMA_REG(2, DCHxINT), 0b11111111); 210 CLR_REG(DMAIFS, ifs); 211 } 212 } 213 214 215 216 /* Peripheral pin configuration. */ 217 218 void config_uart(void) 219 { 220 /* Map U1RX to RPB13. */ 221 222 REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */ 223 224 /* Map U1TX to RPB15. */ 225 226 REG(RPB15R) = 0b0001; /* RPB15R<3:0> = 0001 (U1TX) */ 227 228 /* Set RPB13 to input. */ 229 230 SET_REG(TRISB, 1 << 13); 231 }