thesis_bldc_controller/Examples/NeoPixel Example/DMA.c

85 lines
3.1 KiB
C

#include <samd21g18a.h>
#include <string.h>
#include "DMA.h"
#define MAX_DESCRIPTORS 2
__attribute__((__aligned__(16))) static DmacDescriptor descriptor_section[MAX_DESCRIPTORS];
__attribute__((__aligned__(16))) static DmacDescriptor write_back_section[MAX_DESCRIPTORS];
static int used_channels = 0;
int volatile dma_frame = 0;
void DMA_init(void)
{
static int initialized = 0;
if (!initialized)
{
/* enable peripheral clock */
PM->APBBMASK.bit.DMAC_ = 1;
/* enable AHB master clock */
PM->AHBMASK.bit.DMAC_ = 1;
/* configure DMA controller */
DMAC->BASEADDR.reg = (uint32_t)descriptor_section; // descriptor memory section start
DMAC->WRBADDR.reg = (uint32_t)write_back_section; // descriptor write-back memory section start
DMAC->CTRL.bit.LVLEN0 = 1; // enable level 0 priority
DMAC->CTRL.bit.LVLEN1 = 1; // enable level 1 priority
DMAC->CTRL.bit.LVLEN2 = 1; // enable level 2 priority
DMAC->CTRL.bit.LVLEN3 = 1; // enable level 3 priority
/* DMA is initialized */
initialized = 1;
}
}
/* add the first least significant free channel with its descriptor (TODO: implement linked descriptors) */
void DMA_add_channel(int source, DmacDescriptor *descriptor)
{
/* disable DMA if enabled */
if (DMAC->CTRL.bit.DMAENABLE)
DMAC->CTRL.bit.DMAENABLE = 0;
while (DMAC->CTRL.bit.DMAENABLE)
;
/* add transfer descriptor to transfer descriptor section (before enabling channel!) */
memcpy(descriptor_section + used_channels * sizeof(DmacDescriptor), descriptor, sizeof(DmacDescriptor));
/* configure and enable first least significant free channel */
DMAC->CHID.bit.ID = used_channels++; // use first free channel
DMAC->CHCTRLB.bit.LVL = 0x00; // channel priority level 0
DMAC->CHCTRLB.bit.TRIGACT = 0x02; // one trigger each beat transfer
DMAC->CHCTRLB.bit.TRIGSRC = source; // select trigger source
DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; // enable channel
/* enable DMA block transfer complete interrupt */
DMAC->CHINTENSET.bit.TCMPL = 1; // enable DMA block transfer complete interrupt
NVIC_EnableIRQ(DMAC_IRQn); // enable DMA interrupt in NVIC
}
void DMA_enable(void)
{
/* enable DMA controller */
DMAC->CTRL.bit.DMAENABLE = 1;
}
void DMAC_Handler(void)
{
//static int count;
for (int channel = 0 ; channel < used_channels ; channel++) // check interrupt for every registered channel
{
DMAC->CHID.bit.ID = channel;
if (DMAC->CHINTFLAG.bit.TCMPL && DMAC->CHINTENSET.bit.TCMPL)
{
if (DMAC->CHID.bit.ID == 0x00) // handle SPI transfer complete interrupt
{
DMAC->CHINTFLAG.bit.TCMPL = 1; // acknowledge interrupt
DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; // re-enable DMA channel
}
}
}
}