# HG changeset patch # User Paul Boddie # Date 1539879888 -7200 # Node ID e362ca6522c1e88d087573d60b6c06c857aa0f8e # Parent 6264a477049b3f2366013075c45af662305e0654 Introduced separate configuration functions for DMA auto-enable and chaining. Added an enumeration type for DMA chaining. Added a DMA interrupt flags utility function. Disable individual channel interrupts when configuring DMA channel interrupts. Made the various convenience macros inline functions. diff -r 6264a477049b -r e362ca6522c1 init.c --- a/init.c Thu Oct 18 17:58:45 2018 +0200 +++ b/init.c Thu Oct 18 18:24:48 2018 +0200 @@ -125,18 +125,36 @@ /* Initialise the given channel. */ -void dma_init(int channel, int auto_enable, uint8_t pri) +void dma_init(int channel, uint8_t pri) { if ((channel < DCHMIN) || (channel > DCHMAX)) return; /* Initialise a channel. */ - REG(DMA_REG(channel, DCHxCON)) = (auto_enable ? (1 << 4) : 0) | (pri & 0b11); + REG(DMA_REG(channel, DCHxCON)) = pri & 0b11; REG(DMA_REG(channel, DCHxECON)) = 0; REG(DMA_REG(channel, DCHxINT)) = 0; } +/* Set the channel auto-enable mode. */ + +void dma_set_auto_enable(int channel, int auto_enable) +{ + (auto_enable ? SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 4); +} + +/* Set the channel chaining mode. */ + +void dma_set_chaining(int channel, enum dma_chain chain) +{ + (chain != dma_chain_none ? + SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 5); + + (chain == dma_chain_next ? + SET_REG : CLR_REG)(DMA_REG(channel, DCHxCON), 1 << 8); +} + /* Configure a channel's initiation interrupt. */ void dma_set_interrupt(int channel, uint8_t int_num, int enable) @@ -175,6 +193,11 @@ if ((channel < DCHMIN) || (channel > DCHMAX)) return; + /* Disable channel interrupt and clear interrupt flag. */ + + CLR_REG(DMAIEC, DMA_INT_FLAGS(channel, 1)); + CLR_REG(DMAIFS, DMA_INT_FLAGS(channel, 1)); + /* Produce an interrupt for the provided conditions. */ REG(DMA_REG(channel, DCHxINT)) = conditions << 16; @@ -186,7 +209,7 @@ /* Enable interrupt. */ - SET_REG(DMAIEC, 1 << (channel + DMAINTBASE)); + SET_REG(DMAIEC, DMA_INT_FLAGS(channel, 1)); } /* Enable a DMA channel. */ @@ -320,6 +343,13 @@ return ((pri & 0b111) << 2) | (sub & 0b11); } +/* Return the DMA interrupt flags for combining with a register. */ + +int DMA_INT_FLAGS(int channel, uint8_t flags) +{ + return (flags & 0b1) << (DMAINTBASE + (channel - DCHMIN)); +} + /* Return encoded DMA interrupt priorities for combining with a register. */ uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub) diff -r 6264a477049b -r e362ca6522c1 init.h --- a/init.h Thu Oct 18 17:58:45 2018 +0200 +++ b/init.h Thu Oct 18 18:24:48 2018 +0200 @@ -1,6 +1,8 @@ #ifndef __INIT_H__ #define __INIT_H__ +#include "pic32_c.h" + /* Basic initialisation. */ void init_memory(void); @@ -21,7 +23,11 @@ void init_dma(void); -void dma_init(int channel, int auto_enable, uint8_t pri); +void dma_init(int channel, uint8_t pri); + +void dma_set_auto_enable(int channel, int auto_enable); + +void dma_set_chaining(int channel, enum dma_chain chain); void dma_init_interrupt(int channel, uint8_t conditions, uint8_t pri, uint8_t sub); @@ -35,6 +41,8 @@ uint32_t destination_start_address, uint16_t destination_size, uint16_t cell_size); +int DMA_INT_FLAGS(int channel, uint8_t flags); + uint32_t DMA_IPC_PRI(int channel, uint8_t pri, uint8_t sub); /* Timer configuration. */ @@ -45,11 +53,11 @@ void timer_on(int timer); +int TIMER_INT_FLAGS(int timer, uint8_t flags); + uint32_t TIMER_IPC_PRI(int timer, uint8_t pri, uint8_t sub); uint32_t TIMER_IPC_REG(int timer); -int TIMER_INT_FLAGS(int timer, uint8_t flags); - /* UART configuration. */ void uart_init(int uart, uint32_t baudrate); @@ -59,9 +67,9 @@ void uart_on(int uart); +int UART_INT_FLAGS(int uart, uint8_t flags); + uint32_t UART_IPC_PRI(int uart, uint8_t pri, uint8_t sub); uint32_t UART_IPC_REG(int uart); -int UART_INT_FLAGS(int uart, uint8_t flags); - #endif /* __INIT_H__ */ diff -r 6264a477049b -r e362ca6522c1 pic32_c.h --- a/pic32_c.h Thu Oct 18 17:58:45 2018 +0200 +++ b/pic32_c.h Thu Oct 18 18:24:48 2018 +0200 @@ -9,24 +9,62 @@ /* Access. */ -#define REG(mem) *((volatile uint32_t *) (mem)) +#define REG(mem) *((volatile uint32_t *) (mem)) /* Bit clearing, setting and inverting. */ -#define CLR_REG(mem, val) (REG(mem + CLR) = val) -#define SET_REG(mem, val) (REG(mem + SET) = val) -#define INV_REG(mem, val) (REG(mem + INV) = val) +static inline void CLR_REG(uint32_t mem, uint32_t val) +{ + REG(mem + CLR) = val; +} + +static inline void SET_REG(uint32_t mem, uint32_t val) +{ + REG(mem + SET) = val; +} + +static inline void INV_REG(uint32_t mem, uint32_t val) +{ + REG(mem + INV) = val; +} /* Address translation. */ -#define PHYSICAL(addr) (((uint32_t) addr) - KSEG0_BASE) -#define HW_PHYSICAL(addr) (((uint32_t) addr) - KSEG1_BASE) +static inline uint32_t PHYSICAL(uint32_t addr) +{ + return ((uint32_t) addr) - KSEG0_BASE; +} + +static inline uint32_t HW_PHYSICAL(uint32_t addr) +{ + return ((uint32_t) addr) - KSEG1_BASE; +} /* Register collection access. */ -#define DMA_REG(channel, reg) (DCHBASE + reg + (channel - DCHMIN) * DCHSTEP) -#define TIMER_REG(channel, reg) (TIMERBASE + reg + (channel - TIMERMIN) * TIMERSTEP) -#define UART_REG(channel, reg) (UARTBASE + reg + (channel - UARTMIN) * UARTSTEP) +static inline uint32_t DMA_REG(int channel, uint32_t reg) +{ + return DCHBASE + reg + (channel - DCHMIN) * DCHSTEP; +} + +static inline uint32_t TIMER_REG(int channel, uint32_t reg) +{ + return TIMERBASE + reg + (channel - TIMERMIN) * TIMERSTEP; +} + +static inline uint32_t UART_REG(int channel, uint32_t reg) +{ + return UARTBASE + reg + (channel - UARTMIN) * UARTSTEP; +} + +/* Convenience types. */ + +enum dma_chain +{ + dma_chain_none, + dma_chain_next, + dma_chain_previous, +}; #endif /* __PIC32_C_H__ */