Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
SimpleDMA/SimpleDMA_KL25_46.cpp
- Committer:
- mjr
- Date:
- 2016-02-18
- Revision:
- 47:df7a88cd249c
- Parent:
- 45:c42166b2878c
- Child:
- 48:058ace2aed1d
File content as of revision 47:df7a88cd249c:
#if defined TARGET_KL25Z || defined TARGET_KL46Z #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); 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); // presume no link channels linkMode = 0; linkChannel1 = 0; linkChannel2 = 0; // presume cycle-steal mode cycle_steal = true; } int SimpleDMA::start(uint32_t length) { if (auto_channel) _channel = getFreeChannel(); else while(isBusy()); if (length > DMA_DSR_BCR_BCR_MASK) return -1; irq_owner[_channel] = this; DMA0->DMA[_channel].SAR = _source; DMA0->DMA[_channel].DAR = _destination; DMA0->DMA[_channel].DSR_BCR = length; DMAMUX0->CHCFG[_channel] = _trigger; uint32_t config = DMA_DCR_EINT_MASK | DMA_DCR_ERQ_MASK | DMA_DCR_EADREQ_MASK | (cycle_steal ? DMA_DCR_CS_MASK : 0) | (source_inc << DMA_DCR_SINC_SHIFT) | (destination_inc << DMA_DCR_DINC_SHIFT) | ((linkChannel1 & 3) << DMA_DCR_LCH1_SHIFT) | ((linkChannel2 & 3) << DMA_DCR_LCH2_SHIFT) | ((linkMode & 3) << DMA_DCR_LINKCC_SHIFT); switch (source_size) { case 8: config |= 1 << DMA_DCR_SSIZE_SHIFT; break; case 16: config |= 2 << DMA_DCR_SSIZE_SHIFT; break; } switch (destination_size) { case 8: config |= 1 << DMA_DCR_DSIZE_SHIFT; break; case 16: config |= 2 << DMA_DCR_DSIZE_SHIFT; break; } DMA0->DMA[_channel].DCR = config; //$$$ static int iii; if (iii++ < 3) printf("DMA channel %d: mode %04x, source %08lx, dest %08lx, trigger %d, len %d\r\n", _channel, config, _source, _destination, _trigger, length); //Start - set ENBL bit in the DMAMUX channel config register DMAMUX0->CHCFG[_channel] |= 1<<7; return 0; } void SimpleDMA::link(SimpleDMA &dest, bool all) { linkChannel1 = dest._channel; linkChannel2 = 0; linkMode = all ? 3 : 2; } void SimpleDMA::link(SimpleDMA &dest1, SimpleDMA &dest2) { linkChannel1 = dest1._channel; linkChannel2 = dest2._channel; linkMode = 1; } int SimpleDMA::restart(uint32_t length) { DMA0->DMA[_channel].SAR = _source; DMA0->DMA[_channel].DAR = _destination; DMA0->DMA[_channel].DSR_BCR = length; DMAMUX0->CHCFG[_channel] |= 1<<7; return 0; } 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 & 0xFFFFF); } /*****************************************************************/ uint32_t SimpleDMA::remaining(int channel) { // note that the BCR register always reads with binary 1110 // (if the configuration is correct) or 1111 (if there's an // error in the configuration) in bits 23-20, so we need // to mask these out - only keep bits 19-0 (low-order 20 // bits = 0xFFFFF) return (DMA0->DMA[channel < 0 ? _channel : channel].DSR_BCR & 0xFFFFF); } /*****************************************************************/ void SimpleDMA::irq_handler(void) { DMAMUX0->CHCFG[_channel] = 0; DMA0->DMA[_channel].DSR_BCR |= DMA_DSR_BCR_DONE_MASK ; _callback.call(); } void SimpleDMA::irq_handler0( void ) { if (irq_owner[0]!=NULL) irq_owner[0]->irq_handler(); } void SimpleDMA::irq_handler1( void ) { if (irq_owner[1]!=NULL) irq_owner[1]->irq_handler(); } void SimpleDMA::irq_handler2( void ) { if (irq_owner[2]!=NULL) irq_owner[2]->irq_handler(); } void SimpleDMA::irq_handler3( void ) { if (irq_owner[3]!=NULL) irq_owner[3]->irq_handler(); } #endif