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