A simple library to access the DMA functionality.
Fork of SimpleDMA by
SimpleDMA_KL25.cpp
- Committer:
- Sissors
- Date:
- 2013-12-26
- Revision:
- 3:34f5bf8adfa0
- Parent:
- 2:fe2fcaa72434
- Child:
- 4:c3a84c6c432c
File content as of revision 3:34f5bf8adfa0:
#include "SimpleDMA.h" SimpleDMA *SimpleDMA::irq_owner[4] = {NULL}; SimpleDMA::SimpleDMA(int channel) { this->channel(channel); //Enable DMA SIM->SCGC6 |= 1<<1; //Enable clock to DMA mux SIM->SCGC7 |= 1<<8; //Enable clock to DMA trigger(Trigger_ALWAYS); DCR = (1<<29) + (1<<30); //Set to always use DMAMUX (If no trigger is needed we route via alwayson) NVIC_SetVector(DMA0_IRQn, (uint32_t)&irq_handler0); NVIC_SetVector(DMA1_IRQn, (uint32_t)&irq_handler1); NVIC_SetVector(DMA2_IRQn, (uint32_t)&irq_handler2); NVIC_SetVector(DMA3_IRQn, (uint32_t)&irq_handler3); NVIC_EnableIRQ(DMA0_IRQn); NVIC_EnableIRQ(DMA1_IRQn); NVIC_EnableIRQ(DMA2_IRQn); NVIC_EnableIRQ(DMA3_IRQn); } int SimpleDMA::setAddress(uint32_t address, int wordsize, bool source, bool autoinc) { //Check if it is an allowed address switch ((uint32_t) address >> 20) { case 0x000: case 0x1FF: case 0x200: case 0x400: break; default: return -1; } char _size; switch (wordsize) { case 8: _size = 1; break; case 16: _size = 2; break; case 32: _size = 0; break; default: _size = 1; } //Check if source or destination if (source) { SAR = address; DCR &= ~(7<<20); DCR |= autoinc << 22; DCR |= _size << 20; } else { DAR = address; DCR &= ~(7<<17); DCR |= autoinc << 19; DCR |= _size << 17; } return 0; }; int SimpleDMA::trigger(SimpleDMA_Trigger trig){ CHCFG = trig; return 0; } int SimpleDMA::start(int length) { if (auto_channel) _channel = getFreeChannel(); else while(isBusy()); DMA0->DMA[_channel].DSR_BCR |= DMA_DSR_BCR_DONE_MASK ; if (length > 0xFFFFF) return -1; if (irq_en) { DCR |= (1UL<<31); irq_owner[_channel] = this; } else DCR &= ~(1UL<<31); //Set registers: DMA0->DMA[_channel].SAR = SAR; DMA0->DMA[_channel].DAR = DAR; DMA0->DMA[_channel].DCR = DCR; //Set trigger DMAMUX0->CHCFG[_channel] = CHCFG; //Set length DMA0->DMA[_channel].DSR_BCR = length; //Start DMAMUX0->CHCFG[_channel] |= 1<<7; return 0; } void SimpleDMA::channel(int chan) { if (chan == -1) { auto_channel = true; _channel = 0; } else { auto_channel = false; if (chan >= 0 && chan < DMA_CHANNELS) _channel = chan; else _channel = 3; } } bool SimpleDMA::isBusy( int channel ) { //Busy bit doesn't work as I expect it to do, so just check if counter is at zero //return (DMA0->DMA[_channel].DSR_BCR & (1<<25) == 1<<25); if (channel == -1) channel = _channel; return (DMA0->DMA[channel].DSR_BCR & 0xFFFFFF); } void SimpleDMA::irq_handler(void) { DMAMUX0->CHCFG[_channel] = 0; DMA0->DMA[_channel].DSR_BCR |= DMA_DSR_BCR_DONE_MASK ; _callback.call(); }