1.1 --- a/init.c Wed Oct 17 13:38:01 2018 +0200
1.2 +++ b/init.c Wed Oct 17 17:40:05 2018 +0200
1.3 @@ -1,5 +1,6 @@
1.4 #include "cpu.h"
1.5 #include "pic32_c.h"
1.6 +#include "init.h"
1.7
1.8
1.9
1.10 @@ -40,9 +41,13 @@
1.11 REG(ANSELA) = 0;
1.12 REG(ANSELB) = 0;
1.13
1.14 + /* Set pins as outputs. */
1.15 +
1.16 REG(TRISA) = 0;
1.17 REG(TRISB) = 0;
1.18
1.19 + /* Clear outputs. */
1.20 +
1.21 REG(PORTA) = 0;
1.22 REG(PORTB) = 0;
1.23 }
1.24 @@ -53,6 +58,8 @@
1.25
1.26 void config_uart(void)
1.27 {
1.28 + /* NOTE: Configuring UART1 for specific pins. */
1.29 +
1.30 /* Map U1RX to RPB13. */
1.31
1.32 REG(U1RXR) = 0b0011; /* U1RXR<3:0> = 0011 (RPB13) */
1.33 @@ -99,28 +106,200 @@
1.34
1.35
1.36
1.37 -/* Peripheral configuration. */
1.38 +/* DMA configuration. */
1.39 +
1.40 +void init_dma(void)
1.41 +{
1.42 + /* Disable DMA interrupts. */
1.43 +
1.44 + CLR_REG(DMAIEC, 0b1111 << DMAINTBASE); /* DMA3IE...DMA0IE = 0 */
1.45 +
1.46 + /* Clear DMA interrupt flags. */
1.47 +
1.48 + CLR_REG(DMAIFS, 0b1111 << DMAINTBASE); /* DMA3IF...DMA0IF = 0 */
1.49 +
1.50 + /* Enable DMA. */
1.51 +
1.52 + SET_REG(DMACON, 1 << 15);
1.53 +}
1.54 +
1.55 +/* Initialise the given channel. */
1.56
1.57 -void init_uart(uint8_t pri, uint8_t sub)
1.58 +void dma_init(int channel, int auto_enable, uint8_t pri)
1.59 {
1.60 - CLR_REG(U1MODE, 1 << 15); /* U1MODE<15> = ON = 0 */
1.61 - REG(U1BRG) = 12; /* U1BRG<15:0> = BRG = (FPB / (16 * baudrate)) - 1 = (24000000 / (16 * 115200)) - 1 = 12 */
1.62 + if (channel > DCHMAX)
1.63 + return;
1.64 +
1.65 + /* Initialise a channel. */
1.66 +
1.67 + REG(DMA_REG(channel, DCHxCON)) = (auto_enable ? (1 << 4) : 0) | (pri & 0b11);
1.68 + REG(DMA_REG(channel, DCHxECON)) = 0;
1.69 + REG(DMA_REG(channel, DCHxINT)) = 0;
1.70 +}
1.71 +
1.72 +/* Configure a channel's initiation interrupt. */
1.73 +
1.74 +void dma_set_interrupt(int channel, uint8_t int_num, int enable)
1.75 +{
1.76 + if (channel > DCHMAX)
1.77 + return;
1.78
1.79 - /* Disable interrupt and clear flag. */
1.80 + /* Allow an interrupt to trigger the transfer. */
1.81 +
1.82 + REG(DMA_REG(channel, DCHxECON)) = (int_num << 8) |
1.83 + ((enable ? 1 : 0) << 4);
1.84 +}
1.85 +
1.86 +/* Set a channel's transfer parameters. */
1.87 +
1.88 +void dma_set_transfer(int channel,
1.89 + uint32_t source_start_address, uint16_t source_size,
1.90 + uint32_t destination_start_address, uint16_t destination_size,
1.91 + uint16_t cell_size)
1.92 +{
1.93 + if (channel > DCHMAX)
1.94 + return;
1.95
1.96 - CLR_REG(IEC1, 1 << 8); /* IEC1<8> = U1RIE = 0 */
1.97 - CLR_REG(IFS1, 1 << 8); /* IFS1<8> = U1RIF = 0 */
1.98 + REG(DMA_REG(channel, DCHxSSIZ)) = source_size;
1.99 + REG(DMA_REG(channel, DCHxSSA)) = source_start_address;
1.100 + REG(DMA_REG(channel, DCHxDSIZ)) = destination_size;
1.101 + REG(DMA_REG(channel, DCHxDSA)) = destination_start_address;
1.102 + REG(DMA_REG(channel, DCHxCSIZ)) = cell_size;
1.103 +}
1.104 +
1.105 +/* Configure interrupts caused by the channel. */
1.106
1.107 - /* Set priorities: U1IP = pri; U1IS = sub */
1.108 +void dma_init_interrupt(int channel, uint8_t conditions,
1.109 + uint8_t int_pri, uint8_t int_sub)
1.110 +{
1.111 + if (channel > DCHMAX)
1.112 + return;
1.113
1.114 - REG(IPC8) = (REG(IPC8) & ~0b11111) | ((pri & 0b111) << 2) | (sub & 0b11);
1.115 + /* Produce an interrupt for the provided conditions. */
1.116 +
1.117 + REG(DMA_REG(channel, DCHxINT)) = conditions << 16;
1.118 +
1.119 + /* Set interrupt priorities. */
1.120 +
1.121 + REG(DMAIPC) = (REG(DMAIPC) & ~(DMA_IPC_PRI(channel, 7, 3))) |
1.122 + DMA_IPC_PRI(channel, int_pri, int_sub);
1.123
1.124 /* Enable interrupt. */
1.125
1.126 - SET_REG(IEC1, 1 << 8); /* IEC1<8> = U1RIE = 1 */
1.127 + SET_REG(DMAIEC, 1 << (channel + DMAINTBASE));
1.128 +}
1.129 +
1.130 +/* Enable a DMA channel. */
1.131 +
1.132 +void dma_on(int channel)
1.133 +{
1.134 + if (channel > DCHMAX)
1.135 + return;
1.136 +
1.137 + /* Enable channel. */
1.138 +
1.139 + SET_REG(DMA_REG(channel, DCHxCON), 1 << 7);
1.140 +}
1.141 +
1.142 +/* UART configuration. */
1.143 +
1.144 +void uart_init(int channel, uint32_t baudrate)
1.145 +{
1.146 + /* NOTE: Configured in the initial payload. */
1.147 +
1.148 + uint32_t FPB = 24000000;
1.149 +
1.150 + if ((channel < UARTMIN) || (channel > UARTMAX))
1.151 + return;
1.152 +
1.153 + /* Disable the UART (ON). */
1.154 +
1.155 + CLR_REG(UART_REG(channel, UxMODE), 1 << 15);
1.156 +
1.157 + /* Set the baud rate. For example:
1.158 +
1.159 + UxBRG<15:0> = BRG
1.160 + = (FPB / (16 * baudrate)) - 1
1.161 + = (24000000 / (16 * 115200)) - 1
1.162 + = 12
1.163 + */
1.164 +
1.165 + REG(UART_REG(channel, UxBRG)) = (FPB / (16 * baudrate)) - 1;
1.166 +
1.167 + /* Disable interrupt (UxRIE) and clear flag (UxRIF). */
1.168 +
1.169 + CLR_REG(UARTIEC, 2 << UART_INT_FLAGS(channel));
1.170 + CLR_REG(UARTIFS, 2 << UART_INT_FLAGS(channel));
1.171 +}
1.172 +
1.173 +/* Configure interrupts caused by the UART. */
1.174 +
1.175 +void uart_init_interrupt(int channel, uint8_t pri, uint8_t sub)
1.176 +{
1.177 + if ((channel < UARTMIN) || (channel > UARTMAX))
1.178 + return;
1.179 +
1.180 + /* Set priorities: UxIP = pri; UxIS = sub */
1.181 +
1.182 + REG(UART_IPC_REG(channel)) = (REG(UART_IPC_REG(channel)) & ~UART_IPC_PRI(channel, 7, 3)) |
1.183 + UART_IPC_PRI(channel, pri, sub);
1.184 +
1.185 + /* Enable interrupt (UxRIE). */
1.186 +
1.187 + SET_REG(UARTIEC, 2 << UART_INT_FLAGS(channel));
1.188 +}
1.189 +
1.190 +/* Enable a UART. */
1.191 +
1.192 +void uart_on(int channel)
1.193 +{
1.194 + if ((channel < UARTMIN) || (channel > UARTMAX))
1.195 + return;
1.196 +
1.197 + /* Enable receive (URXEN) and transmit (UTXEN). */
1.198 +
1.199 + SET_REG(UART_REG(channel, UxSTA), (1 << 12) | (1 << 10));
1.200
1.201 /* Start UART. */
1.202
1.203 - SET_REG(U1STA, (1 << 12) | (1 << 10)); /* U1STA<12> = URXEN = 1; U1STA<10> = UTXEN = 1 */
1.204 - SET_REG(U1MODE, 1 << 15); /* U1MODE<15> = ON = 1 */
1.205 + SET_REG(UART_REG(channel, UxMODE), 1 << 15);
1.206 +}
1.207 +
1.208 +
1.209 +
1.210 +/* Utility functions. */
1.211 +
1.212 +/* Return encoded interrupt priorities. */
1.213 +
1.214 +static uint8_t PRI(uint8_t pri, uint8_t sub)
1.215 +{
1.216 + return ((pri & 0b111) << 2) | (sub & 0b11);
1.217 +}
1.218 +
1.219 +/* Return encoded DMA interrupt priorities for combining with a register. */
1.220 +
1.221 +uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub)
1.222 +{
1.223 + return PRI(pri, sub) << (DCHIPCBASE + (channel - DCHMIN) * DCHIPCSTEP);
1.224 }
1.225 +
1.226 +/* Return encoded UART interrupt priorities for combining with a register. */
1.227 +
1.228 +uint32_t UART_IPC_PRI(int channel, uint8_t pri, uint8_t sub)
1.229 +{
1.230 + return PRI(pri, sub) << (channel == 1 ? UART1IPCBASE : UART2IPCBASE);
1.231 +}
1.232 +
1.233 +/* Return the UART interrupt priorities register. */
1.234 +
1.235 +uint32_t UART_IPC_REG(int channel)
1.236 +{
1.237 + return channel == 1 ? UART1IPC : UART2IPC;
1.238 +}
1.239 +
1.240 +/* Return the UART interrupt flags shift offset. */
1.241 +
1.242 +int UART_INT_FLAGS(int channel)
1.243 +{
1.244 + return UARTINTBASE + (channel - UARTMIN) * UARTINTSTEP;
1.245 +}