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