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 < DCHMIN) || (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 < DCHMIN) || (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 < DCHMIN) || (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 pri, uint8_t sub) 174 { 175 if ((channel < DCHMIN) || (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, pri, 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 < DCHMIN) || (channel > DCHMAX)) 197 return; 198 199 /* Enable channel. */ 200 201 SET_REG(DMA_REG(channel, DCHxCON), 1 << 7); 202 } 203 204 205 206 /* Timer configuration. */ 207 208 void timer_init(int timer, uint8_t prescale, uint16_t limit) 209 { 210 /* NOTE: Should convert from the real prescale value. */ 211 212 REG(TIMER_REG(timer, TxCON)) = (prescale & 0b111) << 4; 213 REG(TIMER_REG(timer, TMRx)) = 0; 214 REG(TIMER_REG(timer, PRx)) = limit; 215 } 216 217 /* Configure interrupts caused by the timer. */ 218 219 void timer_init_interrupt(int timer, uint8_t pri, uint8_t sub) 220 { 221 if ((timer < TIMERMIN) || (timer > TIMERMAX)) 222 return; 223 224 /* Set interrupt priorities. */ 225 226 REG(TIMER_IPC_REG(timer)) = (REG(TIMER_IPC_REG(timer)) & 227 ~(TIMER_IPC_PRI(timer, 7, 3))) | 228 TIMER_IPC_PRI(timer, pri, sub); 229 230 /* Enable interrupt. */ 231 232 SET_REG(TIMERIEC, TIMER_INT_FLAGS(timer, TxIE)); 233 } 234 235 /* Enable a timer. */ 236 237 void timer_on(int timer) 238 { 239 if ((timer < TIMERMIN) || (timer > TIMERMAX)) 240 return; 241 242 SET_REG(TIMER_REG(timer, TxCON), 1 << 15); 243 } 244 245 246 247 /* UART configuration. */ 248 249 void uart_init(int uart, uint32_t baudrate) 250 { 251 /* NOTE: Configured in the initial payload. */ 252 253 uint32_t FPB = 24000000; 254 255 if ((uart < UARTMIN) || (uart > UARTMAX)) 256 return; 257 258 /* Disable the UART (ON). */ 259 260 CLR_REG(UART_REG(uart, UxMODE), 1 << 15); 261 262 /* Set the baud rate. For example: 263 264 UxBRG<15:0> = BRG 265 = (FPB / (16 * baudrate)) - 1 266 = (24000000 / (16 * 115200)) - 1 267 = 12 268 */ 269 270 REG(UART_REG(uart, UxBRG)) = (FPB / (16 * baudrate)) - 1; 271 272 /* Disable interrupt (UxRIE) and clear flag (UxRIF). */ 273 274 CLR_REG(UARTIEC, UART_INT_FLAGS(uart, UxRIE)); 275 CLR_REG(UARTIFS, UART_INT_FLAGS(uart, UxRIF)); 276 } 277 278 /* Configure interrupts caused by the UART. */ 279 280 void uart_init_interrupt(int uart, uint8_t conditions, 281 uint8_t pri, uint8_t sub) 282 { 283 if ((uart < UARTMIN) || (uart > UARTMAX)) 284 return; 285 286 /* Set priorities: UxIP = pri; UxIS = sub */ 287 288 REG(UART_IPC_REG(uart)) = (REG(UART_IPC_REG(uart)) & ~UART_IPC_PRI(uart, 7, 3)) | 289 UART_IPC_PRI(uart, pri, sub); 290 291 /* Enable interrupts. */ 292 293 SET_REG(UARTIEC, UART_INT_FLAGS(uart, conditions)); 294 } 295 296 /* Enable a UART. */ 297 298 void uart_on(int uart) 299 { 300 if ((uart < UARTMIN) || (uart > UARTMAX)) 301 return; 302 303 /* Enable receive (URXEN) and transmit (UTXEN). */ 304 305 SET_REG(UART_REG(uart, UxSTA), (1 << 12) | (1 << 10)); 306 307 /* Start UART. */ 308 309 SET_REG(UART_REG(uart, UxMODE), 1 << 15); 310 } 311 312 313 314 /* Utility functions. */ 315 316 /* Return encoded interrupt priorities. */ 317 318 static uint8_t PRI(uint8_t pri, uint8_t sub) 319 { 320 return ((pri & 0b111) << 2) | (sub & 0b11); 321 } 322 323 /* Return encoded DMA interrupt priorities for combining with a register. */ 324 325 uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub) 326 { 327 return PRI(pri, sub) << (DCHIPCBASE + (channel - DCHMIN) * DCHIPCSTEP); 328 } 329 330 /* Return encoded timer interrupt priorities for combining with a register. */ 331 332 uint32_t TIMER_IPC_PRI(int timer, uint8_t pri, uint8_t sub) 333 { 334 (void) timer; 335 return PRI(pri, sub) << TIMERIPCBASE; 336 } 337 338 /* Return the timer interrupt priorities register. */ 339 340 uint32_t TIMER_IPC_REG(int timer) 341 { 342 switch (timer) 343 { 344 case 1: return TIMER1IPC; 345 case 2: return TIMER2IPC; 346 case 3: return TIMER3IPC; 347 case 4: return TIMER4IPC; 348 case 5: return TIMER5IPC; 349 default: return 0; /* should not occur */ 350 } 351 } 352 353 /* Return the timer interrupt flags for combining with a register. */ 354 355 int TIMER_INT_FLAGS(int timer, uint8_t flags) 356 { 357 return (flags & 0b1) << (TIMERINTBASE + (timer - TIMERMIN) * TIMERINTSTEP); 358 } 359 360 /* Return encoded UART interrupt priorities for combining with a register. */ 361 362 uint32_t UART_IPC_PRI(int uart, uint8_t pri, uint8_t sub) 363 { 364 return PRI(pri, sub) << (uart == 1 ? UART1IPCBASE : UART2IPCBASE); 365 } 366 367 /* Return the UART interrupt priorities register. */ 368 369 uint32_t UART_IPC_REG(int uart) 370 { 371 return uart == 1 ? UART1IPC : UART2IPC; 372 } 373 374 /* Return the UART interrupt flags for combining with a register. */ 375 376 int UART_INT_FLAGS(int uart, uint8_t flags) 377 { 378 return (flags & 0b111) << (UARTINTBASE + (uart - UARTMIN) * UARTINTSTEP); 379 }