1 #include "cpu.h" 2 #include "pic32_c.h" 3 #include "init.h" 4 5 6 7 /* Basic memory and pin initialisation. */ 8 9 void init_memory(void) 10 { 11 /* 12 Configure RAM. 13 See: http://microchipdeveloper.com/32bit:mx-arch-exceptions-processor-initialization 14 */ 15 16 uint32_t config = REG(BMXCON); 17 18 /* Set zero wait states for address setup. */ 19 20 config &= ~(1 << 6); /* BMXCON<6> = BMXWSDRM = 0 */ 21 22 /* Set bus arbitration mode. */ 23 24 config &= ~0b111; 25 config |= 0b010; /* BMXCON<2:0> = BMXARB<2:0> = 2 */ 26 27 REG(BMXCON) = config; 28 } 29 30 void init_pins(void) 31 { 32 /* DEVCFG0<2> also needs setting to 0 before the program is run. */ 33 34 CLR_REG(CFGCON, 1 << 3); /* CFGCON<3> = JTAGEN = 0 */ 35 } 36 37 void init_outputs(void) 38 { 39 /* Remove analogue features from pins. */ 40 41 REG(ANSELA) = 0; 42 REG(ANSELB) = 0; 43 44 /* Set pins as outputs. */ 45 46 REG(TRISA) = 0; 47 REG(TRISB) = 0; 48 49 /* Clear outputs. */ 50 51 REG(PORTA) = 0; 52 REG(PORTB) = 0; 53 } 54 55 56 57 /* Peripheral pin configuration. */ 58 59 void config_uart(void) 60 { 61 /* NOTE: Configuring UART1 for specific pins. */ 62 63 /* Map U1RX to RPB13. */ 64 65 REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */ 66 67 /* Map U1TX to RPB15. */ 68 69 REG(RPB15R) = 0b0001; /* RPB15R<3:0> = 0001 (U1TX) */ 70 71 /* Set RPB13 to input. */ 72 73 SET_REG(TRISB, 1 << 13); 74 } 75 76 void lock_config(void) 77 { 78 SET_REG(CFGCON, 1 << 13); /* IOLOCK = 1 */ 79 80 /* Lock the configuration again. */ 81 82 REG(SYSKEY) = 0x33333333; 83 } 84 85 void unlock_config(void) 86 { 87 /* Unlock the configuration register bits. */ 88 89 REG(SYSKEY) = 0; 90 REG(SYSKEY) = 0xAA996655; 91 REG(SYSKEY) = 0x556699AA; 92 93 CLR_REG(CFGCON, 1 << 13); /* IOLOCK = 0 */ 94 } 95 96 97 98 /* Convenience operations. */ 99 100 void interrupts_on(void) 101 { 102 init_interrupts(); 103 enable_interrupts(); 104 handle_error_level(); 105 } 106 107 108 109 /* DMA configuration. */ 110 111 void init_dma(void) 112 { 113 /* Disable DMA interrupts. */ 114 115 CLR_REG(DMAIEC, 0b1111 << DMAINTBASE); /* DMA3IE...DMA0IE = 0 */ 116 117 /* Clear DMA interrupt flags. */ 118 119 CLR_REG(DMAIFS, 0b1111 << DMAINTBASE); /* DMA3IF...DMA0IF = 0 */ 120 121 /* Enable DMA. */ 122 123 SET_REG(DMACON, 1 << 15); 124 } 125 126 /* Initialise the given channel. */ 127 128 void dma_init(int channel, int auto_enable, uint8_t pri) 129 { 130 if (channel > DCHMAX) 131 return; 132 133 /* Initialise a channel. */ 134 135 REG(DMA_REG(channel, DCHxCON)) = (auto_enable ? (1 << 4) : 0) | (pri & 0b11); 136 REG(DMA_REG(channel, DCHxECON)) = 0; 137 REG(DMA_REG(channel, DCHxINT)) = 0; 138 } 139 140 /* Configure a channel's initiation interrupt. */ 141 142 void dma_set_interrupt(int channel, uint8_t int_num, int enable) 143 { 144 if (channel > DCHMAX) 145 return; 146 147 /* Allow an interrupt to trigger the transfer. */ 148 149 REG(DMA_REG(channel, DCHxECON)) = (int_num << 8) | 150 ((enable ? 1 : 0) << 4); 151 } 152 153 /* Set a channel's transfer parameters. */ 154 155 void dma_set_transfer(int channel, 156 uint32_t source_start_address, uint16_t source_size, 157 uint32_t destination_start_address, uint16_t destination_size, 158 uint16_t cell_size) 159 { 160 if (channel > DCHMAX) 161 return; 162 163 REG(DMA_REG(channel, DCHxSSIZ)) = source_size; 164 REG(DMA_REG(channel, DCHxSSA)) = source_start_address; 165 REG(DMA_REG(channel, DCHxDSIZ)) = destination_size; 166 REG(DMA_REG(channel, DCHxDSA)) = destination_start_address; 167 REG(DMA_REG(channel, DCHxCSIZ)) = cell_size; 168 } 169 170 /* Configure interrupts caused by the channel. */ 171 172 void dma_init_interrupt(int channel, uint8_t conditions, 173 uint8_t int_pri, uint8_t int_sub) 174 { 175 if (channel > DCHMAX) 176 return; 177 178 /* Produce an interrupt for the provided conditions. */ 179 180 REG(DMA_REG(channel, DCHxINT)) = conditions << 16; 181 182 /* Set interrupt priorities. */ 183 184 REG(DMAIPC) = (REG(DMAIPC) & ~(DMA_IPC_PRI(channel, 7, 3))) | 185 DMA_IPC_PRI(channel, int_pri, int_sub); 186 187 /* Enable interrupt. */ 188 189 SET_REG(DMAIEC, 1 << (channel + DMAINTBASE)); 190 } 191 192 /* Enable a DMA channel. */ 193 194 void dma_on(int channel) 195 { 196 if (channel > DCHMAX) 197 return; 198 199 /* Enable channel. */ 200 201 SET_REG(DMA_REG(channel, DCHxCON), 1 << 7); 202 } 203 204 /* UART configuration. */ 205 206 void uart_init(int channel, uint32_t baudrate) 207 { 208 /* NOTE: Configured in the initial payload. */ 209 210 uint32_t FPB = 24000000; 211 212 if ((channel < UARTMIN) || (channel > UARTMAX)) 213 return; 214 215 /* Disable the UART (ON). */ 216 217 CLR_REG(UART_REG(channel, UxMODE), 1 << 15); 218 219 /* Set the baud rate. For example: 220 221 UxBRG<15:0> = BRG 222 = (FPB / (16 * baudrate)) - 1 223 = (24000000 / (16 * 115200)) - 1 224 = 12 225 */ 226 227 REG(UART_REG(channel, UxBRG)) = (FPB / (16 * baudrate)) - 1; 228 229 /* Disable interrupt (UxRIE) and clear flag (UxRIF). */ 230 231 CLR_REG(UARTIEC, 2 << UART_INT_FLAGS(channel)); 232 CLR_REG(UARTIFS, 2 << UART_INT_FLAGS(channel)); 233 } 234 235 /* Configure interrupts caused by the UART. */ 236 237 void uart_init_interrupt(int channel, uint8_t pri, uint8_t sub) 238 { 239 if ((channel < UARTMIN) || (channel > UARTMAX)) 240 return; 241 242 /* Set priorities: UxIP = pri; UxIS = sub */ 243 244 REG(UART_IPC_REG(channel)) = (REG(UART_IPC_REG(channel)) & ~UART_IPC_PRI(channel, 7, 3)) | 245 UART_IPC_PRI(channel, pri, sub); 246 247 /* Enable interrupt (UxRIE). */ 248 249 SET_REG(UARTIEC, 2 << UART_INT_FLAGS(channel)); 250 } 251 252 /* Enable a UART. */ 253 254 void uart_on(int channel) 255 { 256 if ((channel < UARTMIN) || (channel > UARTMAX)) 257 return; 258 259 /* Enable receive (URXEN) and transmit (UTXEN). */ 260 261 SET_REG(UART_REG(channel, UxSTA), (1 << 12) | (1 << 10)); 262 263 /* Start UART. */ 264 265 SET_REG(UART_REG(channel, UxMODE), 1 << 15); 266 } 267 268 269 270 /* Utility functions. */ 271 272 /* Return encoded interrupt priorities. */ 273 274 static uint8_t PRI(uint8_t pri, uint8_t sub) 275 { 276 return ((pri & 0b111) << 2) | (sub & 0b11); 277 } 278 279 /* Return encoded DMA interrupt priorities for combining with a register. */ 280 281 uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub) 282 { 283 return PRI(pri, sub) << (DCHIPCBASE + (channel - DCHMIN) * DCHIPCSTEP); 284 } 285 286 /* Return encoded UART interrupt priorities for combining with a register. */ 287 288 uint32_t UART_IPC_PRI(int channel, uint8_t pri, uint8_t sub) 289 { 290 return PRI(pri, sub) << (channel == 1 ? UART1IPCBASE : UART2IPCBASE); 291 } 292 293 /* Return the UART interrupt priorities register. */ 294 295 uint32_t UART_IPC_REG(int channel) 296 { 297 return channel == 1 ? UART1IPC : UART2IPC; 298 } 299 300 /* Return the UART interrupt flags shift offset. */ 301 302 int UART_INT_FLAGS(int channel) 303 { 304 return UARTINTBASE + (channel - UARTMIN) * UARTINTSTEP; 305 }