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, uint8_t pri) 129 { 130 if ((channel < DCHMIN) || (channel > DCHMAX)) 131 return; 132 133 /* Initialise a channel. */ 134 135 REG(DMA_REG(channel, DCHxCON)) = pri & 0b11; 136 REG(DMA_REG(channel, DCHxECON)) = 0; 137 REG(DMA_REG(channel, DCHxINT)) = 0; 138 } 139 140 /* Set the channel auto-enable mode. */ 141 142 void dma_set_auto_enable(int channel, int auto_enable) 143 { 144 (auto_enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 4); 145 } 146 147 /* Set the channel chaining mode. */ 148 149 void dma_set_chaining(int channel, enum dma_chain chain) 150 { 151 (chain != dma_chain_none ? 152 SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 5); 153 154 (chain == dma_chain_next ? 155 SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 8); 156 } 157 158 /* Configure a channel's initiation interrupt. */ 159 160 void dma_set_interrupt(int channel, uint8_t int_num, int enable) 161 { 162 if ((channel < DCHMIN) || (channel > DCHMAX)) 163 return; 164 165 /* Allow an interrupt to trigger the transfer. */ 166 167 REG(DMA_REG(channel, DCHxECON)) = (int_num << 8) | 168 ((enable ? 1 : 0) << 4); 169 } 170 171 /* Set a channel's transfer parameters. */ 172 173 void dma_set_transfer(int channel, 174 uint32_t source_start_address, uint16_t source_size, 175 uint32_t destination_start_address, uint16_t destination_size, 176 uint16_t cell_size) 177 { 178 if ((channel < DCHMIN) || (channel > DCHMAX)) 179 return; 180 181 REG(DMA_REG(channel, DCHxSSIZ)) = source_size; 182 REG(DMA_REG(channel, DCHxSSA)) = source_start_address; 183 REG(DMA_REG(channel, DCHxDSIZ)) = destination_size; 184 REG(DMA_REG(channel, DCHxDSA)) = destination_start_address; 185 REG(DMA_REG(channel, DCHxCSIZ)) = cell_size; 186 } 187 188 /* Configure interrupts caused by the channel. */ 189 190 void dma_init_interrupt(int channel, uint8_t conditions, 191 uint8_t pri, uint8_t sub) 192 { 193 if ((channel < DCHMIN) || (channel > DCHMAX)) 194 return; 195 196 /* Disable channel interrupt and clear interrupt flag. */ 197 198 CLR_REG(DMAIEC, DMA_INT_FLAGS(channel, 1)); 199 CLR_REG(DMAIFS, DMA_INT_FLAGS(channel, 1)); 200 201 /* Produce an interrupt for the provided conditions. */ 202 203 REG(DMA_REG(channel, DCHxINT)) = conditions << 16; 204 205 /* Set interrupt priorities. */ 206 207 REG(DMAIPC) = (REG(DMAIPC) & 208 ~(DMA_IPC_PRI(channel, 7, 3))) | 209 DMA_IPC_PRI(channel, pri, sub); 210 211 /* Enable interrupt. */ 212 213 SET_REG(DMAIEC, DMA_INT_FLAGS(channel, 1)); 214 } 215 216 /* Enable a DMA channel. */ 217 218 void dma_on(int channel) 219 { 220 if ((channel < DCHMIN) || (channel > DCHMAX)) 221 return; 222 223 /* Enable channel. */ 224 225 SET_REG(DMA_REG(channel, DCHxCON), 1 << 7); 226 } 227 228 229 230 /* Output compare configuration. */ 231 232 void oc_init(int unit, uint8_t mode, int timer) 233 { 234 if ((unit < OCMIN) || (unit > OCMAX)) 235 return; 236 237 REG(OC_REG(unit, OCxCON)) = (timer == 3 ? (1 << 3) : 0) | (mode & 0b111); 238 } 239 240 /* Set the start value for the pulse. */ 241 242 void oc_set_pulse(int unit, uint32_t start) 243 { 244 if ((unit < OCMIN) || (unit > OCMAX)) 245 return; 246 247 REG(OC_REG(unit, OCxR)) = start; 248 } 249 250 /* Set the end value for the pulse. */ 251 252 void oc_set_pulse_end(int unit, uint32_t end) 253 { 254 if ((unit < OCMIN) || (unit > OCMAX)) 255 return; 256 257 REG(OC_REG(unit, OCxRS)) = end; 258 } 259 260 /* Configure interrupts caused by the unit. */ 261 262 void oc_init_interrupt(int unit, uint8_t pri, uint8_t sub) 263 { 264 if ((unit < OCMIN) || (unit > OCMAX)) 265 return; 266 267 /* Disable interrupt and clear interrupt flag. */ 268 269 CLR_REG(OCIEC, OC_INT_FLAGS(unit, OCxIE)); 270 CLR_REG(OCIFS, OC_INT_FLAGS(unit, OCxIF)); 271 272 /* Set interrupt priorities. */ 273 274 REG(OC_IPC_REG(unit)) = (REG(OC_IPC_REG(unit)) & 275 ~(OC_IPC_PRI(unit, 7, 3))) | 276 OC_IPC_PRI(unit, pri, sub); 277 278 /* Enable interrupt. */ 279 280 SET_REG(OCIEC, OC_INT_FLAGS(unit, OCxIE)); 281 } 282 283 /* Enable a unit. */ 284 285 void oc_on(int unit) 286 { 287 if ((unit < OCMIN) || (unit > OCMAX)) 288 return; 289 290 SET_REG(OC_REG(unit, OCxCON), 1 << 15); 291 } 292 293 294 295 /* Timer configuration. */ 296 297 void timer_init(int timer, uint8_t prescale, uint16_t limit) 298 { 299 /* NOTE: Should convert from the real prescale value. */ 300 301 REG(TIMER_REG(timer, TxCON)) = (prescale & 0b111) << 4; 302 REG(TIMER_REG(timer, TMRx)) = 0; 303 REG(TIMER_REG(timer, PRx)) = limit; 304 } 305 306 /* Configure interrupts caused by the timer. */ 307 308 void timer_init_interrupt(int timer, uint8_t pri, uint8_t sub) 309 { 310 if ((timer < TIMERMIN) || (timer > TIMERMAX)) 311 return; 312 313 /* Disable interrupt and clear interrupt flag. */ 314 315 CLR_REG(TIMERIEC, TIMER_INT_FLAGS(timer, TxIE)); 316 CLR_REG(TIMERIFS, TIMER_INT_FLAGS(timer, TxIF)); 317 318 /* Set interrupt priorities. */ 319 320 REG(TIMER_IPC_REG(timer)) = (REG(TIMER_IPC_REG(timer)) & 321 ~(TIMER_IPC_PRI(timer, 7, 3))) | 322 TIMER_IPC_PRI(timer, pri, sub); 323 324 /* Enable interrupt. */ 325 326 SET_REG(TIMERIEC, TIMER_INT_FLAGS(timer, TxIE)); 327 } 328 329 /* Enable a timer. */ 330 331 void timer_on(int timer) 332 { 333 if ((timer < TIMERMIN) || (timer > TIMERMAX)) 334 return; 335 336 SET_REG(TIMER_REG(timer, TxCON), 1 << 15); 337 } 338 339 340 341 /* UART configuration. */ 342 343 void uart_init(int uart, uint32_t baudrate) 344 { 345 /* NOTE: Configured in the initial payload. */ 346 347 uint32_t FPB = 24000000; 348 349 if ((uart < UARTMIN) || (uart > UARTMAX)) 350 return; 351 352 /* Disable the UART (ON). */ 353 354 CLR_REG(UART_REG(uart, UxMODE), 1 << 15); 355 356 /* Set the baud rate. For example: 357 358 UxBRG<15:0> = BRG 359 = (FPB / (16 * baudrate)) - 1 360 = (24000000 / (16 * 115200)) - 1 361 = 12 362 */ 363 364 REG(UART_REG(uart, UxBRG)) = (FPB / (16 * baudrate)) - 1; 365 } 366 367 /* Configure interrupts caused by the UART. */ 368 369 void uart_init_interrupt(int uart, uint8_t conditions, 370 uint8_t pri, uint8_t sub) 371 { 372 if ((uart < UARTMIN) || (uart > UARTMAX)) 373 return; 374 375 /* Disable interrupts and clear interrupt flags. */ 376 377 CLR_REG(UARTIEC, UART_INT_FLAGS(uart, UxTIE | UxRIE | UxEIE)); 378 CLR_REG(UARTIFS, UART_INT_FLAGS(uart, UxTIF | UxRIF | UxEIF)); 379 380 /* Set priorities: UxIP = pri; UxIS = sub */ 381 382 REG(UART_IPC_REG(uart)) = (REG(UART_IPC_REG(uart)) & 383 ~UART_IPC_PRI(uart, 7, 3)) | 384 UART_IPC_PRI(uart, pri, sub); 385 386 /* Enable interrupts. */ 387 388 SET_REG(UARTIEC, UART_INT_FLAGS(uart, conditions)); 389 } 390 391 /* Enable a UART. */ 392 393 void uart_on(int uart) 394 { 395 if ((uart < UARTMIN) || (uart > UARTMAX)) 396 return; 397 398 /* Enable receive (URXEN) and transmit (UTXEN). */ 399 400 SET_REG(UART_REG(uart, UxSTA), (1 << 12) | (1 << 10)); 401 402 /* Start UART. */ 403 404 SET_REG(UART_REG(uart, UxMODE), 1 << 15); 405 } 406 407 408 409 /* Utility functions. */ 410 411 /* Return encoded interrupt priorities. */ 412 413 static uint8_t PRI(uint8_t pri, uint8_t sub) 414 { 415 return ((pri & 0b111) << 2) | (sub & 0b11); 416 } 417 418 /* Return the DMA interrupt flags for combining with a register. */ 419 420 int DMA_INT_FLAGS(int channel, uint8_t flags) 421 { 422 return (flags & 0b1) << (DMAINTBASE + (channel - DCHMIN)); 423 } 424 425 /* Return encoded DMA interrupt priorities for combining with a register. */ 426 427 uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub) 428 { 429 return PRI(pri, sub) << (DCHIPCBASE + (channel - DCHMIN) * DCHIPCSTEP); 430 } 431 432 /* Return encoded output compare interrupt priorities for combining with a register. */ 433 434 uint32_t OC_IPC_PRI(int unit, uint8_t pri, uint8_t sub) 435 { 436 (void) unit; 437 return PRI(pri, sub) << OCIPCBASE; 438 } 439 440 /* Return the output compare interrupt priorities register. */ 441 442 uint32_t OC_IPC_REG(int unit) 443 { 444 switch (unit) 445 { 446 case 1: return OC1IPC; 447 case 2: return OC2IPC; 448 case 3: return OC3IPC; 449 case 4: return OC4IPC; 450 case 5: return OC5IPC; 451 default: return 0; /* should not occur */ 452 } 453 } 454 455 /* Return the output compare interrupt flags for combining with a register. */ 456 457 int OC_INT_FLAGS(int unit, uint8_t flags) 458 { 459 return (flags & 0b1) << (OCINTBASE + (unit - OCMIN) * OCINTSTEP); 460 } 461 462 /* Return encoded timer interrupt priorities for combining with a register. */ 463 464 uint32_t TIMER_IPC_PRI(int timer, uint8_t pri, uint8_t sub) 465 { 466 (void) timer; 467 return PRI(pri, sub) << TIMERIPCBASE; 468 } 469 470 /* Return the timer interrupt priorities register. */ 471 472 uint32_t TIMER_IPC_REG(int timer) 473 { 474 switch (timer) 475 { 476 case 1: return TIMER1IPC; 477 case 2: return TIMER2IPC; 478 case 3: return TIMER3IPC; 479 case 4: return TIMER4IPC; 480 case 5: return TIMER5IPC; 481 default: return 0; /* should not occur */ 482 } 483 } 484 485 /* Return the timer interrupt flags for combining with a register. */ 486 487 int TIMER_INT_FLAGS(int timer, uint8_t flags) 488 { 489 return (flags & 0b1) << (TIMERINTBASE + (timer - TIMERMIN) * TIMERINTSTEP); 490 } 491 492 /* Return encoded UART interrupt priorities for combining with a register. */ 493 494 uint32_t UART_IPC_PRI(int uart, uint8_t pri, uint8_t sub) 495 { 496 return PRI(pri, sub) << (uart == 1 ? UART1IPCBASE : UART2IPCBASE); 497 } 498 499 /* Return the UART interrupt priorities register. */ 500 501 uint32_t UART_IPC_REG(int uart) 502 { 503 return uart == 1 ? UART1IPC : UART2IPC; 504 } 505 506 /* Return the UART interrupt flags for combining with a register. */ 507 508 int UART_INT_FLAGS(int uart, uint8_t flags) 509 { 510 return (flags & 0b111) << (UARTINTBASE + (uart - UARTMIN) * UARTINTSTEP); 511 }