Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
SimpleDMA/SimpleDMA_KL25_46.cpp@100:1ff35c07217c, 2019-11-28 (annotated)
- Committer:
- mjr
- Date:
- Thu Nov 28 23:18:23 2019 +0000
- Revision:
- 100:1ff35c07217c
- Parent:
- 76:7f5912b6340e
Added preliminary support for AEAT-6012 and TCD1103 sensors; use continuous averaging for pot sensor analog in; more AltAnalogIn options for timing and resolution
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 | 76:7f5912b6340e | 4 | // DMA - Register Layout Typedef (from mbed MKL25Z4.h) |
mjr | 76:7f5912b6340e | 5 | // Break out the DMA[n] register array as a named struct, |
mjr | 76:7f5912b6340e | 6 | // so that we can create pointers to it. |
mjr | 76:7f5912b6340e | 7 | typedef struct { |
mjr | 76:7f5912b6340e | 8 | __IO uint32_t SAR; /**< Source Address Register, array offset: 0x100, array step: 0x10 */ |
mjr | 76:7f5912b6340e | 9 | __IO uint32_t DAR; /**< Destination Address Register, array offset: 0x104, array step: 0x10 */ |
mjr | 76:7f5912b6340e | 10 | union { /* offset: 0x108, array step: 0x10 */ |
mjr | 76:7f5912b6340e | 11 | __IO uint32_t DSR_BCR; /**< DMA Status Register / Byte Count Register, array offset: 0x108, array step: 0x10 */ |
mjr | 76:7f5912b6340e | 12 | struct { /* offset: 0x108, array step: 0x10 */ |
mjr | 76:7f5912b6340e | 13 | uint8_t RESERVED_0[3]; |
mjr | 76:7f5912b6340e | 14 | __IO uint8_t DSR; /**< DMA_DSR0 register...DMA_DSR3 register., array offset: 0x10B, array step: 0x10 */ |
mjr | 76:7f5912b6340e | 15 | } DMA_DSR_ACCESS8BIT; |
mjr | 76:7f5912b6340e | 16 | }; |
mjr | 76:7f5912b6340e | 17 | __IO uint32_t DCR; /**< DMA Control Register, array offset: 0x10C, array step: 0x10 */ |
mjr | 76:7f5912b6340e | 18 | } DMA_Reg_Type; |
mjr | 76:7f5912b6340e | 19 | typedef struct { |
mjr | 76:7f5912b6340e | 20 | union { /* offset: 0x0 */ |
mjr | 76:7f5912b6340e | 21 | __IO uint8_t REQC_ARR[4]; /**< DMA_REQC0 register...DMA_REQC3 register., array offset: 0x0, array step: 0x1 */ |
mjr | 76:7f5912b6340e | 22 | }; |
mjr | 76:7f5912b6340e | 23 | uint8_t RESERVED_0[252]; |
mjr | 76:7f5912b6340e | 24 | DMA_Reg_Type DMA[4]; |
mjr | 76:7f5912b6340e | 25 | } MyDMA_Type; |
mjr | 45:c42166b2878c | 26 | |
mjr | 45:c42166b2878c | 27 | |
mjr | 45:c42166b2878c | 28 | SimpleDMA *SimpleDMA::irq_owner[4] = {NULL}; |
mjr | 45:c42166b2878c | 29 | |
mjr | 48:058ace2aed1d | 30 | void SimpleDMA::class_init() |
mjr | 48:058ace2aed1d | 31 | { |
mjr | 48:058ace2aed1d | 32 | static bool inited = false; |
mjr | 48:058ace2aed1d | 33 | if (!inited) |
mjr | 48:058ace2aed1d | 34 | { |
mjr | 48:058ace2aed1d | 35 | NVIC_SetVector(DMA0_IRQn, (uint32_t)&irq_handler0); |
mjr | 48:058ace2aed1d | 36 | NVIC_SetVector(DMA1_IRQn, (uint32_t)&irq_handler1); |
mjr | 48:058ace2aed1d | 37 | NVIC_SetVector(DMA2_IRQn, (uint32_t)&irq_handler2); |
mjr | 48:058ace2aed1d | 38 | NVIC_SetVector(DMA3_IRQn, (uint32_t)&irq_handler3); |
mjr | 48:058ace2aed1d | 39 | NVIC_EnableIRQ(DMA0_IRQn); |
mjr | 48:058ace2aed1d | 40 | NVIC_EnableIRQ(DMA1_IRQn); |
mjr | 48:058ace2aed1d | 41 | NVIC_EnableIRQ(DMA2_IRQn); |
mjr | 48:058ace2aed1d | 42 | NVIC_EnableIRQ(DMA3_IRQn); |
mjr | 48:058ace2aed1d | 43 | inited = true; |
mjr | 48:058ace2aed1d | 44 | } |
mjr | 48:058ace2aed1d | 45 | } |
mjr | 48:058ace2aed1d | 46 | |
mjr | 47:df7a88cd249c | 47 | SimpleDMA::SimpleDMA(int channel) |
mjr | 47:df7a88cd249c | 48 | { |
mjr | 48:058ace2aed1d | 49 | class_init(); |
mjr | 54:fd77a6b2f76c | 50 | |
mjr | 54:fd77a6b2f76c | 51 | // remember the channel (-1 means we automatically select on start()) |
mjr | 45:c42166b2878c | 52 | this->channel(channel); |
mjr | 45:c42166b2878c | 53 | |
mjr | 54:fd77a6b2f76c | 54 | // Enable DMA |
mjr | 54:fd77a6b2f76c | 55 | SIM->SCGC6 |= 1<<1; // Enable clock to DMA mux |
mjr | 54:fd77a6b2f76c | 56 | SIM->SCGC7 |= 1<<8; // Enable clock to DMA |
mjr | 45:c42166b2878c | 57 | |
mjr | 54:fd77a6b2f76c | 58 | // use the "always" software trigger by default |
mjr | 45:c42166b2878c | 59 | trigger(Trigger_ALWAYS); |
mjr | 45:c42166b2878c | 60 | |
mjr | 47:df7a88cd249c | 61 | // presume no link channels |
mjr | 47:df7a88cd249c | 62 | linkMode = 0; |
mjr | 47:df7a88cd249c | 63 | linkChannel1 = 0; |
mjr | 47:df7a88cd249c | 64 | linkChannel2 = 0; |
mjr | 45:c42166b2878c | 65 | } |
mjr | 45:c42166b2878c | 66 | |
mjr | 54:fd77a6b2f76c | 67 | int SimpleDMA::start(uint32_t length, bool wait) |
mjr | 48:058ace2aed1d | 68 | { |
mjr | 100:1ff35c07217c | 69 | // prepare the transfer |
mjr | 100:1ff35c07217c | 70 | volatile uint8_t *chcfg = prepare(length, wait); |
mjr | 100:1ff35c07217c | 71 | |
mjr | 100:1ff35c07217c | 72 | // check for errors |
mjr | 100:1ff35c07217c | 73 | if (chcfg == NULL) |
mjr | 100:1ff35c07217c | 74 | return -1; |
mjr | 100:1ff35c07217c | 75 | |
mjr | 100:1ff35c07217c | 76 | // ready to go - set the ENBL bit in the DMAMUX channel config register |
mjr | 100:1ff35c07217c | 77 | // to start the trnasfer |
mjr | 100:1ff35c07217c | 78 | *chcfg |= DMAMUX_CHCFG_ENBL_MASK; |
mjr | 100:1ff35c07217c | 79 | |
mjr | 100:1ff35c07217c | 80 | // return success |
mjr | 100:1ff35c07217c | 81 | return 0; |
mjr | 100:1ff35c07217c | 82 | } |
mjr | 100:1ff35c07217c | 83 | |
mjr | 100:1ff35c07217c | 84 | volatile uint8_t *SimpleDMA::prepare(uint32_t length, bool wait) |
mjr | 100:1ff35c07217c | 85 | { |
mjr | 45:c42166b2878c | 86 | if (auto_channel) |
mjr | 45:c42166b2878c | 87 | _channel = getFreeChannel(); |
mjr | 54:fd77a6b2f76c | 88 | else if (!wait && isBusy()) |
mjr | 100:1ff35c07217c | 89 | return NULL; |
mjr | 54:fd77a6b2f76c | 90 | else { |
mjr | 54:fd77a6b2f76c | 91 | while (isBusy()); |
mjr | 54:fd77a6b2f76c | 92 | } |
mjr | 45:c42166b2878c | 93 | |
mjr | 45:c42166b2878c | 94 | if (length > DMA_DSR_BCR_BCR_MASK) |
mjr | 100:1ff35c07217c | 95 | return NULL; |
mjr | 45:c42166b2878c | 96 | |
mjr | 45:c42166b2878c | 97 | irq_owner[_channel] = this; |
mjr | 76:7f5912b6340e | 98 | |
mjr | 76:7f5912b6340e | 99 | // get pointers to the register locations |
mjr | 76:7f5912b6340e | 100 | volatile uint8_t *chcfg = &DMAMUX0->CHCFG[_channel]; |
mjr | 76:7f5912b6340e | 101 | volatile DMA_Reg_Type *dmareg = (volatile DMA_Reg_Type *)&DMA0->DMA[_channel]; |
mjr | 48:058ace2aed1d | 102 | |
mjr | 48:058ace2aed1d | 103 | // disable the channel while we're setting it up |
mjr | 76:7f5912b6340e | 104 | *chcfg = 0; |
mjr | 54:fd77a6b2f76c | 105 | |
mjr | 54:fd77a6b2f76c | 106 | // set the DONE flag on the channel |
mjr | 76:7f5912b6340e | 107 | dmareg->DSR_BCR = DMA_DSR_BCR_DONE_MASK; |
mjr | 48:058ace2aed1d | 108 | |
mjr | 45:c42166b2878c | 109 | uint32_t config = |
mjr | 45:c42166b2878c | 110 | DMA_DCR_EINT_MASK |
mjr | 45:c42166b2878c | 111 | | DMA_DCR_ERQ_MASK |
mjr | 48:058ace2aed1d | 112 | | DMA_DCR_CS_MASK |
mjr | 54:fd77a6b2f76c | 113 | | ((source_inc & 0x01) << DMA_DCR_SINC_SHIFT) |
mjr | 54:fd77a6b2f76c | 114 | | ((destination_inc & 0x01) << DMA_DCR_DINC_SHIFT) |
mjr | 54:fd77a6b2f76c | 115 | | ((linkChannel1 & 0x03) << DMA_DCR_LCH1_SHIFT) |
mjr | 54:fd77a6b2f76c | 116 | | ((linkChannel2 & 0x03) << DMA_DCR_LCH2_SHIFT) |
mjr | 54:fd77a6b2f76c | 117 | | ((linkMode & 0x03) << DMA_DCR_LINKCC_SHIFT); |
mjr | 47:df7a88cd249c | 118 | |
mjr | 54:fd77a6b2f76c | 119 | switch (source_size) |
mjr | 54:fd77a6b2f76c | 120 | { |
mjr | 54:fd77a6b2f76c | 121 | case 8: |
mjr | 54:fd77a6b2f76c | 122 | config |= 1 << DMA_DCR_SSIZE_SHIFT; |
mjr | 54:fd77a6b2f76c | 123 | break; |
mjr | 54:fd77a6b2f76c | 124 | |
mjr | 54:fd77a6b2f76c | 125 | case 16: |
mjr | 54:fd77a6b2f76c | 126 | config |= 2 << DMA_DCR_SSIZE_SHIFT; |
mjr | 54:fd77a6b2f76c | 127 | break; |
mjr | 45:c42166b2878c | 128 | } |
mjr | 54:fd77a6b2f76c | 129 | |
mjr | 54:fd77a6b2f76c | 130 | switch (destination_size) |
mjr | 54:fd77a6b2f76c | 131 | { |
mjr | 54:fd77a6b2f76c | 132 | case 8: |
mjr | 54:fd77a6b2f76c | 133 | config |= 1 << DMA_DCR_DSIZE_SHIFT; |
mjr | 54:fd77a6b2f76c | 134 | break; |
mjr | 54:fd77a6b2f76c | 135 | |
mjr | 54:fd77a6b2f76c | 136 | case 16: |
mjr | 54:fd77a6b2f76c | 137 | config |= 2 << DMA_DCR_DSIZE_SHIFT; |
mjr | 54:fd77a6b2f76c | 138 | break; |
mjr | 45:c42166b2878c | 139 | } |
mjr | 45:c42166b2878c | 140 | |
mjr | 76:7f5912b6340e | 141 | dmareg->SAR = _source; |
mjr | 76:7f5912b6340e | 142 | dmareg->DAR = _destination; |
mjr | 76:7f5912b6340e | 143 | *chcfg = _trigger; |
mjr | 76:7f5912b6340e | 144 | dmareg->DCR = config; |
mjr | 76:7f5912b6340e | 145 | dmareg->DSR_BCR = length; |
mjr | 47:df7a88cd249c | 146 | |
mjr | 100:1ff35c07217c | 147 | // success - return the channel config register |
mjr | 100:1ff35c07217c | 148 | return chcfg; |
mjr | 45:c42166b2878c | 149 | } |
mjr | 45:c42166b2878c | 150 | |
mjr | 47:df7a88cd249c | 151 | void SimpleDMA::link(SimpleDMA &dest, bool all) |
mjr | 47:df7a88cd249c | 152 | { |
mjr | 47:df7a88cd249c | 153 | linkChannel1 = dest._channel; |
mjr | 47:df7a88cd249c | 154 | linkChannel2 = 0; |
mjr | 47:df7a88cd249c | 155 | linkMode = all ? 3 : 2; |
mjr | 47:df7a88cd249c | 156 | } |
mjr | 47:df7a88cd249c | 157 | |
mjr | 47:df7a88cd249c | 158 | void SimpleDMA::link(SimpleDMA &dest1, SimpleDMA &dest2) |
mjr | 47:df7a88cd249c | 159 | { |
mjr | 47:df7a88cd249c | 160 | linkChannel1 = dest1._channel; |
mjr | 47:df7a88cd249c | 161 | linkChannel2 = dest2._channel; |
mjr | 47:df7a88cd249c | 162 | linkMode = 1; |
mjr | 47:df7a88cd249c | 163 | } |
mjr | 47:df7a88cd249c | 164 | |
mjr | 47:df7a88cd249c | 165 | |
mjr | 47:df7a88cd249c | 166 | bool SimpleDMA::isBusy( int channel ) |
mjr | 47:df7a88cd249c | 167 | { |
mjr | 45:c42166b2878c | 168 | if (channel == -1) |
mjr | 45:c42166b2878c | 169 | channel = _channel; |
mjr | 54:fd77a6b2f76c | 170 | |
mjr | 54:fd77a6b2f76c | 171 | // The busy bit doesn't seem to work as expected. Just check if |
mjr | 54:fd77a6b2f76c | 172 | // counter is at zero - if not, treat it as busy. |
mjr | 54:fd77a6b2f76c | 173 | //return (DMA0->DMA[_channel].DSR_BCR & (1<<25) == 1<<25); |
mjr | 45:c42166b2878c | 174 | return (DMA0->DMA[channel].DSR_BCR & 0xFFFFF); |
mjr | 45:c42166b2878c | 175 | } |
mjr | 45:c42166b2878c | 176 | |
mjr | 45:c42166b2878c | 177 | /*****************************************************************/ |
mjr | 45:c42166b2878c | 178 | uint32_t SimpleDMA::remaining(int channel) |
mjr | 45:c42166b2878c | 179 | { |
mjr | 45:c42166b2878c | 180 | // note that the BCR register always reads with binary 1110 |
mjr | 45:c42166b2878c | 181 | // (if the configuration is correct) or 1111 (if there's an |
mjr | 45:c42166b2878c | 182 | // error in the configuration) in bits 23-20, so we need |
mjr | 45:c42166b2878c | 183 | // to mask these out - only keep bits 19-0 (low-order 20 |
mjr | 45:c42166b2878c | 184 | // bits = 0xFFFFF) |
mjr | 45:c42166b2878c | 185 | return (DMA0->DMA[channel < 0 ? _channel : channel].DSR_BCR & 0xFFFFF); |
mjr | 45:c42166b2878c | 186 | } |
mjr | 45:c42166b2878c | 187 | |
mjr | 45:c42166b2878c | 188 | /*****************************************************************/ |
mjr | 47:df7a88cd249c | 189 | void SimpleDMA::irq_handler(void) |
mjr | 47:df7a88cd249c | 190 | { |
mjr | 45:c42166b2878c | 191 | DMAMUX0->CHCFG[_channel] = 0; |
mjr | 54:fd77a6b2f76c | 192 | DMA0->DMA[_channel].DSR_BCR |= DMA_DSR_BCR_DONE_MASK; |
mjr | 45:c42166b2878c | 193 | _callback.call(); |
mjr | 45:c42166b2878c | 194 | } |
mjr | 45:c42166b2878c | 195 | |
mjr | 47:df7a88cd249c | 196 | void SimpleDMA::irq_handler0( void ) |
mjr | 47:df7a88cd249c | 197 | { |
mjr | 54:fd77a6b2f76c | 198 | if (irq_owner[0] != NULL) |
mjr | 45:c42166b2878c | 199 | irq_owner[0]->irq_handler(); |
mjr | 45:c42166b2878c | 200 | } |
mjr | 45:c42166b2878c | 201 | |
mjr | 47:df7a88cd249c | 202 | void SimpleDMA::irq_handler1( void ) |
mjr | 47:df7a88cd249c | 203 | { |
mjr | 54:fd77a6b2f76c | 204 | if (irq_owner[1] != NULL) |
mjr | 45:c42166b2878c | 205 | irq_owner[1]->irq_handler(); |
mjr | 45:c42166b2878c | 206 | } |
mjr | 45:c42166b2878c | 207 | |
mjr | 47:df7a88cd249c | 208 | void SimpleDMA::irq_handler2( void ) |
mjr | 47:df7a88cd249c | 209 | { |
mjr | 54:fd77a6b2f76c | 210 | if (irq_owner[2] != NULL) |
mjr | 45:c42166b2878c | 211 | irq_owner[2]->irq_handler(); |
mjr | 45:c42166b2878c | 212 | } |
mjr | 45:c42166b2878c | 213 | |
mjr | 47:df7a88cd249c | 214 | void SimpleDMA::irq_handler3( void ) |
mjr | 47:df7a88cd249c | 215 | { |
mjr | 54:fd77a6b2f76c | 216 | if (irq_owner[3] != NULL) |
mjr | 45:c42166b2878c | 217 | irq_owner[3]->irq_handler(); |
mjr | 45:c42166b2878c | 218 | } |
mjr | 54:fd77a6b2f76c | 219 | #endif |