/** @file dma.h * Module handling Direct Memory Access controller * * The module provides functions to configure the dma channels and controller * transfers */ //--includes-------------------------------------------------------------------- #include "dma.h" #include "dma_regs.h" #include "nvic.h" #include "rcc.h" //--local definitions----------------------------------------------------------- static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel, enum DmaConfig config_mask, void* periph, void* mem, uint16_t size); static uint32_t periph_regs(enum DmaPeriph periph, volatile struct DMA** regs); //--local variables------------------------------------------------------------- static volatile struct DMA* const dma1 = (struct DMA*)DMA1_BASE_ADDRESS; static volatile struct DMA* const dma2 = (struct DMA*)DMA2_BASE_ADDRESS; static DmaCallback dm1_callbacks[7]; static DmaCallback dm2_callbacks[5]; //--public functions------------------------------------------------------------ void dma_configure(enum DmaPeriph dma, enum DmaChannel channel, enum DmaConfig config_mask, void* periph, void* mem, uint16_t size, DmaCallback callback) { //reset peripheral first, to ensure proper configuration dma_reset(dma, channel); switch (dma) { case DMA_PERIPH_1: rcc_enable(RCC_AHB_DMA1, RCC_APB1_NONE, RCC_APB2_NONE); configure_dma(dma1, channel, config_mask, periph, mem, size); if (callback) { dm1_callbacks[channel] = callback; nvic_enable(NVIC_IRQ_DMA1_CHANNEL1 + channel); } break; case DMA_PERIPH_2: rcc_enable(RCC_AHB_DMA2, RCC_APB1_NONE, RCC_APB2_NONE); configure_dma(dma2, channel, config_mask, periph, mem, size); if (callback) { dm2_callbacks[channel] = callback; nvic_enable(NVIC_IRQ_DMA2_CHANNEL1 + channel); } break; default: break; } } void dma_reset(enum DmaPeriph dma, enum DmaChannel channel) { volatile struct DMA* periph; //first, disable IRQs switch (dma) { case DMA_PERIPH_1: periph = dma1; nvic_disable(NVIC_IRQ_DMA1_CHANNEL1 + channel); break; case DMA_PERIPH_2: periph = dma2; nvic_disable(NVIC_IRQ_DMA2_CHANNEL1 + channel); break; default: return; break; } //then, set all registers to reset value volatile struct DMA_CHANNEL* regs = &periph->CHANNELS[channel]; regs->CCR.word = 0; regs->CNDTR.word = 0; regs->CMAR = 0; regs->CPAR = 0; } //--local functions------------------------------------------------------------- static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel, enum DmaConfig config_mask, void* periph, void* mem, uint16_t size) { volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel]; //registers should already be at reset value, apply new config regs->CCR.word = config_mask; reg_write(regs->CNDTR, DMA_CNDTR_NDT, size); regs->CPAR = (uint32_t)periph; regs->CMAR = (uint32_t)mem; //only enable channel when everything is configured reg_set(regs->CCR, DMA_CCR_EN); } static uint32_t periph_regs(enum DmaPeriph periph, volatile struct DMA** regs) { switch (periph) { case DMA_PERIPH_1: *regs = dma1; break; case DMA_PERIPH_2: *regs = dma2; break; default: return 1; break; } return 0; } //--ISRs------------------------------------------------------------------------ void hdr_dma1_channel1(void) { nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL1); enum DmaIRQSource src = (dma1->IFCR.word >> 1) & 0x7; reg_set(dma1->IFCR, DMA_IFCR_CGIF1); dm1_callbacks[0](src); } void hdr_dma1_channel2(void) { nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL2); enum DmaIRQSource src = (dma1->IFCR.word >> 5) & 0x7; reg_set(dma1->IFCR, DMA_IFCR_CGIF2); dm1_callbacks[1](src); } void hdr_dma1_channel3(void) { nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL3); enum DmaIRQSource src = (dma1->IFCR.word >> 9) & 0x7; reg_set(dma1->IFCR, DMA_IFCR_CGIF3); dm1_callbacks[2](src); } void hdr_dma1_channel4(void) { nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL4); enum DmaIRQSource src = (dma1->IFCR.word >> 13) & 0x7; reg_set(dma1->IFCR, DMA_IFCR_CGIF4); dm1_callbacks[3](src); } void hdr_dma1_channel5(void) { nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL5); enum DmaIRQSource src = (dma1->IFCR.word >> 17) & 0x7; reg_set(dma1->IFCR, DMA_IFCR_CGIF5); dm1_callbacks[4](src); } void hdr_dma1_channel6(void) { nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL6); enum DmaIRQSource src = (dma1->IFCR.word >> 21) & 0x7; reg_set(dma1->IFCR, DMA_IFCR_CGIF6); dm1_callbacks[5](src); } void hdr_dma1_channel7(void) { nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL7); enum DmaIRQSource src = (dma1->IFCR.word >> 25) & 0x7; reg_set(dma1->IFCR, DMA_IFCR_CGIF7); dm1_callbacks[6](src); } void hdr_dma2_channel1(void) { nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL1); enum DmaIRQSource src = (dma2->IFCR.word >> 1) & 0x7; reg_set(dma2->IFCR, DMA_IFCR_CGIF1); dm1_callbacks[0](src); } void hdr_dma2_channel2(void) { nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL2); enum DmaIRQSource src = (dma2->IFCR.word >> 5) & 0x7; reg_set(dma2->IFCR, DMA_IFCR_CGIF2); dm2_callbacks[1](src); } void hdr_dma2_channel3(void) { nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL3); enum DmaIRQSource src = (dma2->IFCR.word >> 9) & 0x7; reg_set(dma2->IFCR, DMA_IFCR_CGIF3); dm2_callbacks[2](src); } void hdr_dma2_channel4_5(void) { nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL4_5); enum DmaIRQSource src = (dma2->IFCR.word >> 13) & 0x7; if (src != 0) { reg_set(dma2->IFCR, DMA_IFCR_CGIF4); dm1_callbacks[3](src); } src = (dma2->IFCR.word >> 17) & 0x7; if (src != 0) { reg_set(dma2->IFCR, DMA_IFCR_CGIF5); dm1_callbacks[4](src); } }