1.1 --- a/init.c Thu Oct 18 21:05:18 2018 +0200
1.2 +++ b/init.c Thu Oct 18 22:45:55 2018 +0200
1.3 @@ -204,7 +204,8 @@
1.4
1.5 /* Set interrupt priorities. */
1.6
1.7 - REG(DMAIPC) = (REG(DMAIPC) & ~(DMA_IPC_PRI(channel, 7, 3))) |
1.8 + REG(DMAIPC) = (REG(DMAIPC) &
1.9 + ~(DMA_IPC_PRI(channel, 7, 3))) |
1.10 DMA_IPC_PRI(channel, pri, sub);
1.11
1.12 /* Enable interrupt. */
1.13 @@ -226,6 +227,71 @@
1.14
1.15
1.16
1.17 +/* Output compare configuration. */
1.18 +
1.19 +void oc_init(int unit, uint8_t mode, int timer)
1.20 +{
1.21 + if ((unit < OCMIN) || (unit > OCMAX))
1.22 + return;
1.23 +
1.24 + REG(OC_REG(unit, OCxCON)) = (timer == 3 ? (1 << 3) : 0) | (mode & 0b111);
1.25 +}
1.26 +
1.27 +/* Set the start value for the pulse. */
1.28 +
1.29 +void oc_set_pulse(int unit, uint32_t start)
1.30 +{
1.31 + if ((unit < OCMIN) || (unit > OCMAX))
1.32 + return;
1.33 +
1.34 + REG(OC_REG(unit, OCxR)) = start;
1.35 +}
1.36 +
1.37 +/* Set the end value for the pulse. */
1.38 +
1.39 +void oc_set_pulse_end(int unit, uint32_t end)
1.40 +{
1.41 + if ((unit < OCMIN) || (unit > OCMAX))
1.42 + return;
1.43 +
1.44 + REG(OC_REG(unit, OCxRS)) = end;
1.45 +}
1.46 +
1.47 +/* Configure interrupts caused by the unit. */
1.48 +
1.49 +void oc_init_interrupt(int unit, uint8_t pri, uint8_t sub)
1.50 +{
1.51 + if ((unit < OCMIN) || (unit > OCMAX))
1.52 + return;
1.53 +
1.54 + /* Disable interrupt and clear interrupt flag. */
1.55 +
1.56 + CLR_REG(OCIEC, OC_INT_FLAGS(unit, OCxIE));
1.57 + CLR_REG(OCIFS, OC_INT_FLAGS(unit, OCxIF));
1.58 +
1.59 + /* Set interrupt priorities. */
1.60 +
1.61 + REG(OC_IPC_REG(unit)) = (REG(OC_IPC_REG(unit)) &
1.62 + ~(OC_IPC_PRI(unit, 7, 3))) |
1.63 + OC_IPC_PRI(unit, pri, sub);
1.64 +
1.65 + /* Enable interrupt. */
1.66 +
1.67 + SET_REG(OCIEC, OC_INT_FLAGS(unit, OCxIE));
1.68 +}
1.69 +
1.70 +/* Enable a unit. */
1.71 +
1.72 +void oc_on(int unit)
1.73 +{
1.74 + if ((unit < OCMIN) || (unit > OCMAX))
1.75 + return;
1.76 +
1.77 + SET_REG(OC_REG(unit, OCxCON), 1 << 15);
1.78 +}
1.79 +
1.80 +
1.81 +
1.82 /* Timer configuration. */
1.83
1.84 void timer_init(int timer, uint8_t prescale, uint16_t limit)
1.85 @@ -244,6 +310,11 @@
1.86 if ((timer < TIMERMIN) || (timer > TIMERMAX))
1.87 return;
1.88
1.89 + /* Disable interrupt and clear interrupt flag. */
1.90 +
1.91 + CLR_REG(TIMERIEC, TIMER_INT_FLAGS(timer, TxIE));
1.92 + CLR_REG(TIMERIFS, TIMER_INT_FLAGS(timer, TxIF));
1.93 +
1.94 /* Set interrupt priorities. */
1.95
1.96 REG(TIMER_IPC_REG(timer)) = (REG(TIMER_IPC_REG(timer)) &
1.97 @@ -291,11 +362,6 @@
1.98 */
1.99
1.100 REG(UART_REG(uart, UxBRG)) = (FPB / (16 * baudrate)) - 1;
1.101 -
1.102 - /* Disable interrupt (UxRIE) and clear flag (UxRIF). */
1.103 -
1.104 - CLR_REG(UARTIEC, UART_INT_FLAGS(uart, UxRIE));
1.105 - CLR_REG(UARTIFS, UART_INT_FLAGS(uart, UxRIF));
1.106 }
1.107
1.108 /* Configure interrupts caused by the UART. */
1.109 @@ -306,10 +372,16 @@
1.110 if ((uart < UARTMIN) || (uart > UARTMAX))
1.111 return;
1.112
1.113 + /* Disable interrupts and clear interrupt flags. */
1.114 +
1.115 + CLR_REG(UARTIEC, UART_INT_FLAGS(uart, UxTIE | UxRIE | UxEIE));
1.116 + CLR_REG(UARTIFS, UART_INT_FLAGS(uart, UxTIF | UxRIF | UxEIF));
1.117 +
1.118 /* Set priorities: UxIP = pri; UxIS = sub */
1.119
1.120 - REG(UART_IPC_REG(uart)) = (REG(UART_IPC_REG(uart)) & ~UART_IPC_PRI(uart, 7, 3)) |
1.121 - UART_IPC_PRI(uart, pri, sub);
1.122 + REG(UART_IPC_REG(uart)) = (REG(UART_IPC_REG(uart)) &
1.123 + ~UART_IPC_PRI(uart, 7, 3)) |
1.124 + UART_IPC_PRI(uart, pri, sub);
1.125
1.126 /* Enable interrupts. */
1.127
1.128 @@ -357,6 +429,36 @@
1.129 return PRI(pri, sub) << (DCHIPCBASE + (channel - DCHMIN) * DCHIPCSTEP);
1.130 }
1.131
1.132 +/* Return encoded output compare interrupt priorities for combining with a register. */
1.133 +
1.134 +uint32_t OC_IPC_PRI(int unit, uint8_t pri, uint8_t sub)
1.135 +{
1.136 + (void) unit;
1.137 + return PRI(pri, sub) << OCIPCBASE;
1.138 +}
1.139 +
1.140 +/* Return the output compare interrupt priorities register. */
1.141 +
1.142 +uint32_t OC_IPC_REG(int unit)
1.143 +{
1.144 + switch (unit)
1.145 + {
1.146 + case 1: return OC1IPC;
1.147 + case 2: return OC2IPC;
1.148 + case 3: return OC3IPC;
1.149 + case 4: return OC4IPC;
1.150 + case 5: return OC5IPC;
1.151 + default: return 0; /* should not occur */
1.152 + }
1.153 +}
1.154 +
1.155 +/* Return the output compare interrupt flags for combining with a register. */
1.156 +
1.157 +int OC_INT_FLAGS(int unit, uint8_t flags)
1.158 +{
1.159 + return (flags & 0b1) << (OCINTBASE + (unit - OCMIN) * OCINTSTEP);
1.160 +}
1.161 +
1.162 /* Return encoded timer interrupt priorities for combining with a register. */
1.163
1.164 uint32_t TIMER_IPC_PRI(int timer, uint8_t pri, uint8_t sub)
2.1 --- a/init.h Thu Oct 18 21:05:18 2018 +0200
2.2 +++ b/init.h Thu Oct 18 22:45:55 2018 +0200
2.3 @@ -47,6 +47,23 @@
2.4
2.5 /* Timer configuration. */
2.6
2.7 +void oc_init(int unit, uint8_t mode, int timer);
2.8 +
2.9 +void oc_set_pulse(int unit, uint32_t start);
2.10 +
2.11 +void oc_set_pulse_end(int unit, uint32_t end);
2.12 +
2.13 +void oc_init_interrupt(int unit, uint8_t pri, uint8_t sub);
2.14 +
2.15 +void oc_on(int unit);
2.16 +
2.17 +int OC_INT_FLAGS(int unit, uint8_t flags);
2.18 +
2.19 +uint32_t OC_IPC_PRI(int unit, uint8_t pri, uint8_t sub);
2.20 +uint32_t OC_IPC_REG(int unit);
2.21 +
2.22 +/* Timer configuration. */
2.23 +
2.24 void timer_init(int timer, uint8_t prescale, uint16_t limit);
2.25
2.26 void timer_init_interrupt(int timer, uint8_t pri, uint8_t sub);
3.1 --- a/main.c Thu Oct 18 21:05:18 2018 +0200
3.2 +++ b/main.c Thu Oct 18 22:45:55 2018 +0200
3.3 @@ -47,27 +47,40 @@
3.4 HW_PHYSICAL(UART_REG(1, UxTXREG)), 1,
3.5 1);
3.6
3.7 - /* Enable DMA on the preceding channel's completion, with Timer3 initiating
3.8 - transfers, raising a transfer completion interrupt. */
3.9 + /* Enable DMA on the preceding channel's completion, with OC1 initiating
3.10 + transfers, raising a transfer completion interrupt to be handled. */
3.11
3.12 dma_init(1, 3);
3.13 dma_set_chaining(1, dma_chain_previous);
3.14 - dma_set_interrupt(1, T3, 1);
3.15 + dma_set_interrupt(1, OC1, 1);
3.16 dma_set_transfer(1, PHYSICAL((uint32_t) message2), sizeof(message2) - 1,
3.17 HW_PHYSICAL(UART_REG(1, UxTXREG)), 1,
3.18 1);
3.19 dma_init_interrupt(1, 0b00001000, 7, 3);
3.20
3.21 - /* Configure timers. */
3.22 + /* Configure a timer for the first DMA channel whose interrupt condition
3.23 + drives the transfer but is not handled (having a lower priority than the
3.24 + CPU. */
3.25
3.26 timer_init(2, 0b111, 60000);
3.27 timer_init_interrupt(2, 1, 3);
3.28 timer_on(2);
3.29
3.30 - timer_init(3, 0b111, 40000);
3.31 - timer_init_interrupt(3, 1, 3);
3.32 + /* Configure a timer for the output compare unit below. */
3.33 +
3.34 + timer_init(3, 0b111, 20000);
3.35 timer_on(3);
3.36
3.37 + /* Configure output compare in dual compare (continuous output) mode using
3.38 + Timer3 as time base. The interrupt condition drives the second DMA
3.39 + channel but is not handled (having a lower priority than the CPU). */
3.40 +
3.41 + oc_init(1, 0b101, 3);
3.42 + oc_set_pulse(1, 10000);
3.43 + oc_set_pulse_end(1, 20000);
3.44 + oc_init_interrupt(1, 1, 3);
3.45 + oc_on(1);
3.46 +
3.47 /* Set UART interrupt priority above CPU priority to process events. */
3.48
3.49 uart_init(1, 115200);
4.1 --- a/pic32.h Thu Oct 18 21:05:18 2018 +0200
4.2 +++ b/pic32.h Thu Oct 18 22:45:55 2018 +0200
4.3 @@ -8,16 +8,6 @@
4.4 * PIC32MX1XX/2XX 28/36/44-pin Family Data Sheet
4.5 */
4.6
4.7 -#define OC1CON 0xBF803000
4.8 -#define OC1R 0xBF803010
4.9 -#define OC1RS 0xBF803020
4.10 -#define OC2CON 0xBF803200
4.11 -#define OC2R 0xBF803210
4.12 -#define OC2RS 0xBF803220
4.13 -#define OC3CON 0xBF803400
4.14 -#define OC3R 0xBF803410
4.15 -#define OC3RS 0xBF803420
4.16 -
4.17 #define PMCON 0xBF807000
4.18 #define PMMODE 0xBF807010
4.19 #define PMADDR 0xBF807020
4.20 @@ -110,10 +100,46 @@
4.21 #define DMAIEC IEC1
4.22 #define DMAIFS IFS1
4.23 #define DMAINTBASE 28
4.24 +
4.25 #define DMAIPC IPC10
4.26 #define DCHIPCBASE 0
4.27 #define DCHIPCSTEP 8
4.28
4.29 +/* Output compare conveniences. */
4.30 +
4.31 +#define OC1CON 0xBF803000
4.32 +#define OC2CON 0xBF803200
4.33 +#define OC3CON 0xBF803400
4.34 +#define OC4CON 0xBF803600
4.35 +#define OC5CON 0xBF803800
4.36 +
4.37 +#define OCMIN 1
4.38 +#define OCMAX 5
4.39 +#define OCBASE OC1CON
4.40 +#define OCSTEP (OC2CON - OC1CON)
4.41 +
4.42 +#define OCxCON 0x00
4.43 +#define OCxR 0x10
4.44 +#define OCxRS 0x20
4.45 +
4.46 +#define OCIEC IEC0
4.47 +
4.48 +#define OCxIE 1
4.49 +
4.50 +#define OCIFS IFS0
4.51 +
4.52 +#define OCxIF 1
4.53 +
4.54 +#define OCINTBASE 7
4.55 +#define OCINTSTEP 5
4.56 +
4.57 +#define OC1IPC IPC1
4.58 +#define OC2IPC IPC2
4.59 +#define OC3IPC IPC3
4.60 +#define OC4IPC IPC4
4.61 +#define OC5IPC IPC5
4.62 +#define OCIPCBASE 16
4.63 +
4.64 /* Timer conveniences. */
4.65
4.66 #define T1CON 0xBF800600
4.67 @@ -195,6 +221,11 @@
4.68 #define DMA1 61
4.69 #define DMA2 62
4.70 #define DMA3 63
4.71 +#define OC1 7
4.72 +#define OC2 12
4.73 +#define OC3 17
4.74 +#define OC4 22
4.75 +#define OC5 27
4.76 #define T1 4
4.77 #define T2 9
4.78 #define T3 14
5.1 --- a/pic32_c.h Thu Oct 18 21:05:18 2018 +0200
5.2 +++ b/pic32_c.h Thu Oct 18 22:45:55 2018 +0200
5.3 @@ -47,14 +47,19 @@
5.4 return DCHBASE + reg + (channel - DCHMIN) * DCHSTEP;
5.5 }
5.6
5.7 -static inline uint32_t TIMER_REG(int channel, uint32_t reg)
5.8 +static inline uint32_t OC_REG(int unit, uint32_t reg)
5.9 {
5.10 - return TIMERBASE + reg + (channel - TIMERMIN) * TIMERSTEP;
5.11 + return OCBASE + reg + (unit - OCMIN) * OCSTEP;
5.12 }
5.13
5.14 -static inline uint32_t UART_REG(int channel, uint32_t reg)
5.15 +static inline uint32_t TIMER_REG(int timer, uint32_t reg)
5.16 {
5.17 - return UARTBASE + reg + (channel - UARTMIN) * UARTSTEP;
5.18 + return TIMERBASE + reg + (timer - TIMERMIN) * TIMERSTEP;
5.19 +}
5.20 +
5.21 +static inline uint32_t UART_REG(int uart, uint32_t reg)
5.22 +{
5.23 + return UARTBASE + reg + (uart - UARTMIN) * UARTSTEP;
5.24 }
5.25
5.26 /* Convenience types. */