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