Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
SimpleDMA/SimpleDMA_KL25_46.cpp@45:c42166b2878c, 2016-02-15 (annotated)
- Committer:
- mjr
- Date:
- Mon Feb 15 20:30:32 2016 +0000
- Revision:
- 45:c42166b2878c
- Child:
- 47:df7a88cd249c
More work in progress on CCD speedups;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mjr | 45:c42166b2878c | 1 | #if defined TARGET_KL25Z || defined TARGET_KL46Z |
mjr | 45:c42166b2878c | 2 | #include "SimpleDMA.h" |
mjr | 45:c42166b2878c | 3 | |
mjr | 45:c42166b2878c | 4 | |
mjr | 45:c42166b2878c | 5 | |
mjr | 45:c42166b2878c | 6 | SimpleDMA *SimpleDMA::irq_owner[4] = {NULL}; |
mjr | 45:c42166b2878c | 7 | |
mjr | 45:c42166b2878c | 8 | SimpleDMA::SimpleDMA(int channel) { |
mjr | 45:c42166b2878c | 9 | this->channel(channel); |
mjr | 45:c42166b2878c | 10 | |
mjr | 45:c42166b2878c | 11 | //Enable DMA |
mjr | 45:c42166b2878c | 12 | SIM->SCGC6 |= 1<<1; //Enable clock to DMA mux |
mjr | 45:c42166b2878c | 13 | SIM->SCGC7 |= 1<<8; //Enable clock to DMA |
mjr | 45:c42166b2878c | 14 | |
mjr | 45:c42166b2878c | 15 | trigger(Trigger_ALWAYS); |
mjr | 45:c42166b2878c | 16 | |
mjr | 45:c42166b2878c | 17 | NVIC_SetVector(DMA0_IRQn, (uint32_t)&irq_handler0); |
mjr | 45:c42166b2878c | 18 | NVIC_SetVector(DMA1_IRQn, (uint32_t)&irq_handler1); |
mjr | 45:c42166b2878c | 19 | NVIC_SetVector(DMA2_IRQn, (uint32_t)&irq_handler2); |
mjr | 45:c42166b2878c | 20 | NVIC_SetVector(DMA3_IRQn, (uint32_t)&irq_handler3); |
mjr | 45:c42166b2878c | 21 | NVIC_EnableIRQ(DMA0_IRQn); |
mjr | 45:c42166b2878c | 22 | NVIC_EnableIRQ(DMA1_IRQn); |
mjr | 45:c42166b2878c | 23 | NVIC_EnableIRQ(DMA2_IRQn); |
mjr | 45:c42166b2878c | 24 | NVIC_EnableIRQ(DMA3_IRQn); |
mjr | 45:c42166b2878c | 25 | |
mjr | 45:c42166b2878c | 26 | // presume cycle-steal mode |
mjr | 45:c42166b2878c | 27 | cycle_steal = true; |
mjr | 45:c42166b2878c | 28 | } |
mjr | 45:c42166b2878c | 29 | |
mjr | 45:c42166b2878c | 30 | // Figure the circular buffer MOD bit pattern (SMOD or DMOD) |
mjr | 45:c42166b2878c | 31 | // for a given circular buffer size. The buffer size is |
mjr | 45:c42166b2878c | 32 | // required to be a power of 2 from 16 to 256K. |
mjr | 45:c42166b2878c | 33 | static uint32_t modsize_to_modbits(uint32_t siz) |
mjr | 45:c42166b2878c | 34 | { |
mjr | 45:c42166b2878c | 35 | // The bit pattern is such that 2^(bits+3), so we basically |
mjr | 45:c42166b2878c | 36 | // need to take the base-2 log of the size. Zero has the |
mjr | 45:c42166b2878c | 37 | // special meaning that the circular buffer is disabled. |
mjr | 45:c42166b2878c | 38 | uint32_t bits = 0; |
mjr | 45:c42166b2878c | 39 | for (bits = 0 ; siz >= 16 ; siz >>= 1, ++bits) ; |
mjr | 45:c42166b2878c | 40 | |
mjr | 45:c42166b2878c | 41 | // return the result, which can't be over binary 1111 |
mjr | 45:c42166b2878c | 42 | return bits & 0xF; |
mjr | 45:c42166b2878c | 43 | } |
mjr | 45:c42166b2878c | 44 | |
mjr | 45:c42166b2878c | 45 | int SimpleDMA::start(uint32_t length) { |
mjr | 45:c42166b2878c | 46 | if (auto_channel) |
mjr | 45:c42166b2878c | 47 | _channel = getFreeChannel(); |
mjr | 45:c42166b2878c | 48 | else |
mjr | 45:c42166b2878c | 49 | while(isBusy()); |
mjr | 45:c42166b2878c | 50 | |
mjr | 45:c42166b2878c | 51 | if (length > DMA_DSR_BCR_BCR_MASK) |
mjr | 45:c42166b2878c | 52 | return -1; |
mjr | 45:c42166b2878c | 53 | |
mjr | 45:c42166b2878c | 54 | irq_owner[_channel] = this; |
mjr | 45:c42166b2878c | 55 | |
mjr | 45:c42166b2878c | 56 | DMA0->DMA[_channel].SAR = _source; |
mjr | 45:c42166b2878c | 57 | DMA0->DMA[_channel].DAR = _destination; |
mjr | 45:c42166b2878c | 58 | DMA0->DMA[_channel].DSR_BCR = length; |
mjr | 45:c42166b2878c | 59 | DMAMUX0->CHCFG[_channel] = _trigger; |
mjr | 45:c42166b2878c | 60 | |
mjr | 45:c42166b2878c | 61 | uint32_t config = |
mjr | 45:c42166b2878c | 62 | DMA_DCR_EINT_MASK |
mjr | 45:c42166b2878c | 63 | | DMA_DCR_ERQ_MASK |
mjr | 45:c42166b2878c | 64 | | (cycle_steal ? DMA_DCR_CS_MASK : 0) |
mjr | 45:c42166b2878c | 65 | | (source_inc << DMA_DCR_SINC_SHIFT) |
mjr | 45:c42166b2878c | 66 | | (modsize_to_modbits(source_mod) << DMA_DCR_SMOD_SHIFT) |
mjr | 45:c42166b2878c | 67 | | (destination_inc << DMA_DCR_DINC_SHIFT) |
mjr | 45:c42166b2878c | 68 | | (modsize_to_modbits(destination_mod) << DMA_DCR_DMOD_SHIFT); |
mjr | 45:c42166b2878c | 69 | switch (source_size) { |
mjr | 45:c42166b2878c | 70 | case 8: |
mjr | 45:c42166b2878c | 71 | config |= 1 << DMA_DCR_SSIZE_SHIFT; |
mjr | 45:c42166b2878c | 72 | break; |
mjr | 45:c42166b2878c | 73 | case 16: |
mjr | 45:c42166b2878c | 74 | config |= 2 << DMA_DCR_SSIZE_SHIFT; |
mjr | 45:c42166b2878c | 75 | break; |
mjr | 45:c42166b2878c | 76 | } |
mjr | 45:c42166b2878c | 77 | switch (destination_size) { |
mjr | 45:c42166b2878c | 78 | case 8: |
mjr | 45:c42166b2878c | 79 | config |= 1 << DMA_DCR_DSIZE_SHIFT; |
mjr | 45:c42166b2878c | 80 | break; |
mjr | 45:c42166b2878c | 81 | case 16: |
mjr | 45:c42166b2878c | 82 | config |= 2 << DMA_DCR_DSIZE_SHIFT; |
mjr | 45:c42166b2878c | 83 | break; |
mjr | 45:c42166b2878c | 84 | } |
mjr | 45:c42166b2878c | 85 | |
mjr | 45:c42166b2878c | 86 | DMA0->DMA[_channel].DCR = config; |
mjr | 45:c42166b2878c | 87 | |
mjr | 45:c42166b2878c | 88 | //Start |
mjr | 45:c42166b2878c | 89 | DMAMUX0->CHCFG[_channel] |= 1<<7; |
mjr | 45:c42166b2878c | 90 | |
mjr | 45:c42166b2878c | 91 | return 0; |
mjr | 45:c42166b2878c | 92 | } |
mjr | 45:c42166b2878c | 93 | |
mjr | 45:c42166b2878c | 94 | int SimpleDMA::restart(uint32_t length) |
mjr | 45:c42166b2878c | 95 | { |
mjr | 45:c42166b2878c | 96 | DMA0->DMA[_channel].SAR = _source; |
mjr | 45:c42166b2878c | 97 | DMA0->DMA[_channel].DAR = _destination; |
mjr | 45:c42166b2878c | 98 | DMA0->DMA[_channel].DSR_BCR = length; |
mjr | 45:c42166b2878c | 99 | DMAMUX0->CHCFG[_channel] |= 1<<7; |
mjr | 45:c42166b2878c | 100 | return 0; |
mjr | 45:c42166b2878c | 101 | } |
mjr | 45:c42166b2878c | 102 | |
mjr | 45:c42166b2878c | 103 | bool SimpleDMA::isBusy( int channel ) { |
mjr | 45:c42166b2878c | 104 | //Busy bit doesn't work as I expect it to do, so just check if counter is at zero |
mjr | 45:c42166b2878c | 105 | //return (DMA0->DMA[_channel].DSR_BCR & (1<<25) == 1<<25); |
mjr | 45:c42166b2878c | 106 | if (channel == -1) |
mjr | 45:c42166b2878c | 107 | channel = _channel; |
mjr | 45:c42166b2878c | 108 | |
mjr | 45:c42166b2878c | 109 | return (DMA0->DMA[channel].DSR_BCR & 0xFFFFF); |
mjr | 45:c42166b2878c | 110 | } |
mjr | 45:c42166b2878c | 111 | |
mjr | 45:c42166b2878c | 112 | /*****************************************************************/ |
mjr | 45:c42166b2878c | 113 | uint32_t SimpleDMA::remaining(int channel) |
mjr | 45:c42166b2878c | 114 | { |
mjr | 45:c42166b2878c | 115 | // note that the BCR register always reads with binary 1110 |
mjr | 45:c42166b2878c | 116 | // (if the configuration is correct) or 1111 (if there's an |
mjr | 45:c42166b2878c | 117 | // error in the configuration) in bits 23-20, so we need |
mjr | 45:c42166b2878c | 118 | // to mask these out - only keep bits 19-0 (low-order 20 |
mjr | 45:c42166b2878c | 119 | // bits = 0xFFFFF) |
mjr | 45:c42166b2878c | 120 | return (DMA0->DMA[channel < 0 ? _channel : channel].DSR_BCR & 0xFFFFF); |
mjr | 45:c42166b2878c | 121 | } |
mjr | 45:c42166b2878c | 122 | |
mjr | 45:c42166b2878c | 123 | /*****************************************************************/ |
mjr | 45:c42166b2878c | 124 | void SimpleDMA::irq_handler(void) { |
mjr | 45:c42166b2878c | 125 | DMAMUX0->CHCFG[_channel] = 0; |
mjr | 45:c42166b2878c | 126 | DMA0->DMA[_channel].DSR_BCR |= DMA_DSR_BCR_DONE_MASK ; |
mjr | 45:c42166b2878c | 127 | _callback.call(); |
mjr | 45:c42166b2878c | 128 | } |
mjr | 45:c42166b2878c | 129 | |
mjr | 45:c42166b2878c | 130 | void SimpleDMA::irq_handler0( void ) { |
mjr | 45:c42166b2878c | 131 | if (irq_owner[0]!=NULL) |
mjr | 45:c42166b2878c | 132 | irq_owner[0]->irq_handler(); |
mjr | 45:c42166b2878c | 133 | } |
mjr | 45:c42166b2878c | 134 | |
mjr | 45:c42166b2878c | 135 | void SimpleDMA::irq_handler1( void ) { |
mjr | 45:c42166b2878c | 136 | if (irq_owner[1]!=NULL) |
mjr | 45:c42166b2878c | 137 | irq_owner[1]->irq_handler(); |
mjr | 45:c42166b2878c | 138 | } |
mjr | 45:c42166b2878c | 139 | |
mjr | 45:c42166b2878c | 140 | void SimpleDMA::irq_handler2( void ) { |
mjr | 45:c42166b2878c | 141 | if (irq_owner[2]!=NULL) |
mjr | 45:c42166b2878c | 142 | irq_owner[2]->irq_handler(); |
mjr | 45:c42166b2878c | 143 | } |
mjr | 45:c42166b2878c | 144 | |
mjr | 45:c42166b2878c | 145 | void SimpleDMA::irq_handler3( void ) { |
mjr | 45:c42166b2878c | 146 | if (irq_owner[3]!=NULL) |
mjr | 45:c42166b2878c | 147 | irq_owner[3]->irq_handler(); |
mjr | 45:c42166b2878c | 148 | } |
mjr | 45:c42166b2878c | 149 | #endif |