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 +}
2.1 --- a/init.h Wed Oct 17 13:38:01 2018 +0200
2.2 +++ b/init.h Wed Oct 17 17:40:05 2018 +0200
2.3 @@ -17,8 +17,39 @@
2.4
2.5 void interrupts_on(void);
2.6
2.7 -/* Peripheral configuration. */
2.8 +/* DMA configuration. */
2.9 +
2.10 +void init_dma(void);
2.11 +
2.12 +void dma_init(int channel, int auto_enable, uint8_t pri);
2.13 +
2.14 +void dma_init_interrupt(int channel, uint8_t conditions,
2.15 + uint8_t int_pri, uint8_t int_sub);
2.16 +
2.17 +void dma_on(int channel);
2.18 +
2.19 +void dma_set_interrupt(int channel, uint8_t int_num, int enable);
2.20
2.21 -void init_uart(uint8_t pri, uint8_t sub);
2.22 +void dma_set_transfer(int channel,
2.23 + uint32_t source_start_address, uint16_t source_size,
2.24 + uint32_t destination_start_address, uint16_t destination_size,
2.25 + uint16_t cell_size);
2.26 +
2.27 +/* UART configuration. */
2.28 +
2.29 +void uart_init(int channel, uint32_t baudrate);
2.30 +
2.31 +void uart_init_interrupt(int channel, uint8_t pri, uint8_t sub);
2.32 +
2.33 +void uart_on(int channel);
2.34 +
2.35 +/* Utility functions. */
2.36 +
2.37 +uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub);
2.38 +
2.39 +uint32_t UART_IPC_PRI(int channel, uint8_t pri, uint8_t sub);
2.40 +uint32_t UART_IPC_REG(int channel);
2.41 +
2.42 +int UART_INT_FLAGS(int channel);
2.43
2.44 #endif /* __INIT_H__ */
3.1 --- a/main.c Wed Oct 17 13:38:01 2018 +0200
3.2 +++ b/main.c Wed Oct 17 17:40:05 2018 +0200
3.3 @@ -1,11 +1,13 @@
3.4 #include "pic32_c.h"
3.5 #include "init.h"
3.6
3.7 +static const char message[] = "Hello!\r\n";
3.8 +
3.9 static void uart_write(char c)
3.10 {
3.11 - while (REG(U1STA) & (1 << 9)); /* UTXBF (buffer full) */
3.12 + while (REG(UART_REG(1, UxSTA)) & (1 << 9)); /* UTXBF (buffer full) */
3.13
3.14 - REG(U1TXREG) = c;
3.15 + REG(UART_REG(1, UxTXREG)) = c;
3.16 }
3.17
3.18 static void bits(uint32_t reg)
3.19 @@ -39,7 +41,11 @@
3.20 /* Invert outputs (LED). */
3.21
3.22 INV_REG(port, pins);
3.23 - bits(IFS1);
3.24 + bits(DMA_REG(0, DCHxCON));
3.25 + bits(DMA_REG(0, DCHxECON));
3.26 + bits(DMA_REG(0, DCHxINT));
3.27 +
3.28 + /* SET_REG(DMA_REG(0, DCHxECON), 1 << 7); */
3.29 }
3.30 }
3.31
3.32 @@ -53,7 +59,21 @@
3.33 config_uart();
3.34 lock_config();
3.35
3.36 - init_uart(7, 3);
3.37 + /* Initiate DMA on UART receive interrupt. */
3.38 +
3.39 + init_dma();
3.40 + dma_init(0, 0, 3);
3.41 + dma_set_interrupt(0, U1RX, 1);
3.42 + dma_set_transfer(0, PHYSICAL(message), sizeof(message) - 1,
3.43 + HW_PHYSICAL(UART_REG(1, UxTXREG)), 1,
3.44 + 1);
3.45 + dma_on(0);
3.46 +
3.47 + /* Set UART interrupt priority below CPU priority. */
3.48 +
3.49 + uart_init(1, 115200);
3.50 + uart_init_interrupt(1, 1, 3);
3.51 + uart_on(1);
3.52
3.53 interrupts_on();
3.54
3.55 @@ -67,19 +87,18 @@
3.56
3.57 void interrupt_handler(void)
3.58 {
3.59 - /* Check for a UART receive interrupt condition (U1RIF). */
3.60 + /* Check for a UART receive interrupt condition (UxRIF). */
3.61
3.62 - if (!(REG(IFS1) & (1 << 8)))
3.63 - return;
3.64 -
3.65 - /* Write the received data back. */
3.66 + if (REG(IFS1) & (1 << 8))
3.67 + {
3.68 + /* Write the received data back. */
3.69
3.70 - INV_REG(PORTA, 1 << 2);
3.71 + while (REG(UART_REG(1, UxSTA)) & 1)
3.72 + uart_write((char) REG(UART_REG(1, UxRXREG)));
3.73
3.74 - while (REG(U1STA) & 1)
3.75 - uart_write((char) REG(U1RXREG));
3.76 + /* Clear the UART interrupt condition. */
3.77
3.78 - /* Clear the UART interrupt condition. */
3.79 -
3.80 - CLR_REG(IFS1, 1 << 8);
3.81 + CLR_REG(IFS1, 1 << 8);
3.82 + INV_REG(PORTA, 1 << 2);
3.83 + }
3.84 }
4.1 --- a/pic32.h Wed Oct 17 13:38:01 2018 +0200
4.2 +++ b/pic32.h Wed Oct 17 17:40:05 2018 +0200
4.3 @@ -1,10 +1,10 @@
4.4 #ifndef __PIC32_H__
4.5 #define __PIC32_H__
4.6
4.7 -/* See...
4.8 +/* Peripheral addresses.
4.9 + * See...
4.10 * TABLE 4-1: SFR MEMORYMAP
4.11 * TABLE 11-3: PORTA REGISTER MAP
4.12 - * 11.2 CLR, SET and INV Registers
4.13 * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet
4.14 */
4.15
4.16 @@ -28,12 +28,6 @@
4.17 #define TMR3 0xBF800A10
4.18 #define PR3 0xBF800A20
4.19
4.20 -#define U1MODE 0xBF806000
4.21 -#define U1STA 0xBF806010
4.22 -#define U1TXREG 0xBF806020
4.23 -#define U1RXREG 0xBF806030
4.24 -#define U1BRG 0xBF806040
4.25 -
4.26 #define PMCON 0xBF807000
4.27 #define PMMODE 0xBF807010
4.28 #define PMADDR 0xBF807020
4.29 @@ -71,8 +65,13 @@
4.30 #define IEC1 0xBF881070
4.31 #define IPC1 0xBF8810A0
4.32 #define IPC2 0xBF8810B0
4.33 +#define IPC3 0xBF8810C0
4.34 +#define IPC4 0xBF8810D0
4.35 +#define IPC5 0xBF8810E0
4.36 +#define IPC6 0xBF8810F0
4.37 #define IPC7 0xBF881100
4.38 #define IPC8 0xBF881110
4.39 +#define IPC9 0xBF881120
4.40 #define IPC10 0xBF881130
4.41
4.42 #define BMXCON 0xBF882000
4.43 @@ -81,32 +80,6 @@
4.44 #define BMXDUPBA 0xBF882030
4.45 #define BMXDRMSZ 0xBF882040
4.46
4.47 -#define DMACON 0xBF883000
4.48 -#define DCH0CON 0xBF883060
4.49 -#define DCH0ECON 0xBF883070
4.50 -#define DCH0INT 0xBF883080
4.51 -#define DCH0SSA 0xBF883090
4.52 -#define DCH0DSA 0xBF8830A0
4.53 -#define DCH0SSIZ 0xBF8830B0
4.54 -#define DCH0DSIZ 0xBF8830C0
4.55 -#define DCH0CSIZ 0xBF8830F0
4.56 -#define DCH1CON 0xBF883120
4.57 -#define DCH1ECON 0xBF883130
4.58 -#define DCH1INT 0xBF883140
4.59 -#define DCH1SSA 0xBF883150
4.60 -#define DCH1DSA 0xBF883160
4.61 -#define DCH1SSIZ 0xBF883170
4.62 -#define DCH1DSIZ 0xBF883180
4.63 -#define DCH1CSIZ 0xBF8831B0
4.64 -#define DCH2CON 0xBF8831E0
4.65 -#define DCH2ECON 0xBF8831F0
4.66 -#define DCH2INT 0xBF883200
4.67 -#define DCH2SSA 0xBF883210
4.68 -#define DCH2DSA 0xBF883220
4.69 -#define DCH2SSIZ 0xBF883230
4.70 -#define DCH2DSIZ 0xBF883240
4.71 -#define DCH2CSIZ 0xBF883270
4.72 -
4.73 #define ANSELA 0xBF886000
4.74 #define TRISA 0xBF886010
4.75 #define PORTA 0xBF886020
4.76 @@ -118,8 +91,77 @@
4.77 #define LATB 0xBF886130
4.78 #define ODCB 0xBF886140
4.79
4.80 -#define CLR 0x4
4.81 -#define SET 0x8
4.82 -#define INV 0xC
4.83 +/* DMA conveniences. */
4.84 +
4.85 +#define DMACON 0xBF883000
4.86 +#define DCH0CON 0xBF883060
4.87 +#define DCH1CON 0xBF883120
4.88 +#define DCH2CON 0xBF8831E0
4.89 +#define DCH3CON 0xBF8832A0
4.90 +
4.91 +#define DCHMIN 0
4.92 +#define DCHMAX 3
4.93 +#define DCHBASE DCH0CON
4.94 +#define DCHSTEP (DCH1CON - DCH0CON)
4.95 +
4.96 +#define DCHxCON 0x00
4.97 +#define DCHxECON 0x10
4.98 +#define DCHxINT 0x20
4.99 +#define DCHxSSA 0x30
4.100 +#define DCHxDSA 0x40
4.101 +#define DCHxSSIZ 0x50
4.102 +#define DCHxDSIZ 0x80
4.103 +#define DCHxCSIZ 0x90
4.104 +
4.105 +#define DMAIEC IEC1
4.106 +#define DMAIFS IFS1
4.107 +#define DMAINTBASE 28
4.108 +#define DMAIPC IPC10
4.109 +#define DCHIPCBASE 0
4.110 +#define DCHIPCSTEP 8
4.111 +
4.112 +/* UART conveniences. */
4.113 +
4.114 +#define U1MODE 0xBF806000
4.115 +#define U2MODE 0xBF806200
4.116 +
4.117 +#define UARTMIN 1
4.118 +#define UARTMAX 2
4.119 +#define UARTBASE U1MODE
4.120 +#define UARTSTEP (U2MODE - U1MODE)
4.121 +
4.122 +#define UxMODE 0x00
4.123 +#define UxSTA 0x10
4.124 +#define UxTXREG 0x20
4.125 +#define UxRXREG 0x30
4.126 +#define UxBRG 0x40
4.127 +
4.128 +#define UARTIEC IEC1
4.129 +#define UARTIFS IFS1
4.130 +#define UARTINTBASE 7
4.131 +#define UARTINTSTEP 14
4.132 +#define UART1IPC IPC8
4.133 +#define UART1IPCBASE 0
4.134 +#define UART2IPC IPC9
4.135 +#define UART2IPCBASE 8
4.136 +
4.137 +/* Interrupt numbers.
4.138 + * See...
4.139 + * TABLE 7-1: INTERRUPT IRQ, VECTOR AND BIT LOCATION
4.140 + * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet
4.141 + */
4.142 +
4.143 +#define U1RX 40
4.144 +#define U2RX 54
4.145 +
4.146 +/* Address modifiers.
4.147 + * See...
4.148 + * 11.2 CLR, SET and INV Registers
4.149 + * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet
4.150 + */
4.151 +
4.152 +#define CLR 0x4
4.153 +#define SET 0x8
4.154 +#define INV 0xC
4.155
4.156 #endif /* __PIC32_H__ */
5.1 --- a/pic32_c.h Wed Oct 17 13:38:01 2018 +0200
5.2 +++ b/pic32_c.h Wed Oct 17 17:40:05 2018 +0200
5.3 @@ -22,6 +22,11 @@
5.4 #define PHYSICAL(addr) (((uint32_t) addr) - KSEG0_BASE)
5.5 #define HW_PHYSICAL(addr) (((uint32_t) addr) - KSEG1_BASE)
5.6
5.7 +/* Register collection access. */
5.8 +
5.9 +#define DMA_REG(channel, reg) (DCHBASE + reg + (channel - DCHMIN) * DCHSTEP)
5.10 +#define UART_REG(channel, reg) (UARTBASE + reg + (channel - UARTMIN) * UARTSTEP)
5.11 +
5.12 #endif /* __PIC32_C_H__ */
5.13
5.14 #endif /* __ASSEMBLER__ */