An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.
Dependencies: mbed FastIO FastPWM USBDevice
Fork of Pinscape_Controller by
SimpleDMA_KL25_46.cpp
00001 #if defined TARGET_KL25Z || defined TARGET_KL46Z 00002 #include "SimpleDMA.h" 00003 00004 // DMA - Register Layout Typedef (from mbed MKL25Z4.h) 00005 // Break out the DMA[n] register array as a named struct, 00006 // so that we can create pointers to it. 00007 typedef struct { 00008 __IO uint32_t SAR; /**< Source Address Register, array offset: 0x100, array step: 0x10 */ 00009 __IO uint32_t DAR; /**< Destination Address Register, array offset: 0x104, array step: 0x10 */ 00010 union { /* offset: 0x108, array step: 0x10 */ 00011 __IO uint32_t DSR_BCR; /**< DMA Status Register / Byte Count Register, array offset: 0x108, array step: 0x10 */ 00012 struct { /* offset: 0x108, array step: 0x10 */ 00013 uint8_t RESERVED_0[3]; 00014 __IO uint8_t DSR; /**< DMA_DSR0 register...DMA_DSR3 register., array offset: 0x10B, array step: 0x10 */ 00015 } DMA_DSR_ACCESS8BIT; 00016 }; 00017 __IO uint32_t DCR; /**< DMA Control Register, array offset: 0x10C, array step: 0x10 */ 00018 } DMA_Reg_Type; 00019 typedef struct { 00020 union { /* offset: 0x0 */ 00021 __IO uint8_t REQC_ARR[4]; /**< DMA_REQC0 register...DMA_REQC3 register., array offset: 0x0, array step: 0x1 */ 00022 }; 00023 uint8_t RESERVED_0[252]; 00024 DMA_Reg_Type DMA[4]; 00025 } MyDMA_Type; 00026 00027 00028 SimpleDMA *SimpleDMA::irq_owner[4] = {NULL}; 00029 00030 void SimpleDMA::class_init() 00031 { 00032 static bool inited = false; 00033 if (!inited) 00034 { 00035 NVIC_SetVector(DMA0_IRQn, (uint32_t)&irq_handler0); 00036 NVIC_SetVector(DMA1_IRQn, (uint32_t)&irq_handler1); 00037 NVIC_SetVector(DMA2_IRQn, (uint32_t)&irq_handler2); 00038 NVIC_SetVector(DMA3_IRQn, (uint32_t)&irq_handler3); 00039 NVIC_EnableIRQ(DMA0_IRQn); 00040 NVIC_EnableIRQ(DMA1_IRQn); 00041 NVIC_EnableIRQ(DMA2_IRQn); 00042 NVIC_EnableIRQ(DMA3_IRQn); 00043 inited = true; 00044 } 00045 } 00046 00047 SimpleDMA::SimpleDMA(int channel) 00048 { 00049 class_init(); 00050 00051 // remember the channel (-1 means we automatically select on start()) 00052 this->channel(channel); 00053 00054 // Enable DMA 00055 SIM->SCGC6 |= 1<<1; // Enable clock to DMA mux 00056 SIM->SCGC7 |= 1<<8; // Enable clock to DMA 00057 00058 // use the "always" software trigger by default 00059 trigger(Trigger_ALWAYS); 00060 00061 // presume no link channels 00062 linkMode = 0; 00063 linkChannel1 = 0; 00064 linkChannel2 = 0; 00065 } 00066 00067 int SimpleDMA::start(uint32_t length, bool wait) 00068 { 00069 // prepare the transfer 00070 volatile uint8_t *chcfg = prepare(length, wait); 00071 00072 // check for errors 00073 if (chcfg == NULL) 00074 return -1; 00075 00076 // ready to go - set the ENBL bit in the DMAMUX channel config register 00077 // to start the trnasfer 00078 *chcfg |= DMAMUX_CHCFG_ENBL_MASK; 00079 00080 // return success 00081 return 0; 00082 } 00083 00084 volatile uint8_t *SimpleDMA::prepare(uint32_t length, bool wait) 00085 { 00086 if (auto_channel) 00087 _channel = getFreeChannel(); 00088 else if (!wait && isBusy()) 00089 return NULL; 00090 else { 00091 while (isBusy()); 00092 } 00093 00094 if (length > DMA_DSR_BCR_BCR_MASK) 00095 return NULL; 00096 00097 irq_owner[_channel] = this; 00098 00099 // get pointers to the register locations 00100 volatile uint8_t *chcfg = &DMAMUX0->CHCFG[_channel]; 00101 volatile DMA_Reg_Type *dmareg = (volatile DMA_Reg_Type *)&DMA0->DMA[_channel]; 00102 00103 // disable the channel while we're setting it up 00104 *chcfg = 0; 00105 00106 // set the DONE flag on the channel 00107 dmareg->DSR_BCR = DMA_DSR_BCR_DONE_MASK; 00108 00109 uint32_t config = 00110 DMA_DCR_EINT_MASK 00111 | DMA_DCR_ERQ_MASK 00112 | DMA_DCR_CS_MASK 00113 | ((source_inc & 0x01) << DMA_DCR_SINC_SHIFT) 00114 | ((destination_inc & 0x01) << DMA_DCR_DINC_SHIFT) 00115 | ((linkChannel1 & 0x03) << DMA_DCR_LCH1_SHIFT) 00116 | ((linkChannel2 & 0x03) << DMA_DCR_LCH2_SHIFT) 00117 | ((linkMode & 0x03) << DMA_DCR_LINKCC_SHIFT); 00118 00119 switch (source_size) 00120 { 00121 case 8: 00122 config |= 1 << DMA_DCR_SSIZE_SHIFT; 00123 break; 00124 00125 case 16: 00126 config |= 2 << DMA_DCR_SSIZE_SHIFT; 00127 break; 00128 } 00129 00130 switch (destination_size) 00131 { 00132 case 8: 00133 config |= 1 << DMA_DCR_DSIZE_SHIFT; 00134 break; 00135 00136 case 16: 00137 config |= 2 << DMA_DCR_DSIZE_SHIFT; 00138 break; 00139 } 00140 00141 dmareg->SAR = _source; 00142 dmareg->DAR = _destination; 00143 *chcfg = _trigger; 00144 dmareg->DCR = config; 00145 dmareg->DSR_BCR = length; 00146 00147 // success - return the channel config register 00148 return chcfg; 00149 } 00150 00151 void SimpleDMA::link(SimpleDMA &dest, bool all) 00152 { 00153 linkChannel1 = dest._channel; 00154 linkChannel2 = 0; 00155 linkMode = all ? 3 : 2; 00156 } 00157 00158 void SimpleDMA::link(SimpleDMA &dest1, SimpleDMA &dest2) 00159 { 00160 linkChannel1 = dest1._channel; 00161 linkChannel2 = dest2._channel; 00162 linkMode = 1; 00163 } 00164 00165 00166 bool SimpleDMA::isBusy( int channel ) 00167 { 00168 if (channel == -1) 00169 channel = _channel; 00170 00171 // The busy bit doesn't seem to work as expected. Just check if 00172 // counter is at zero - if not, treat it as busy. 00173 //return (DMA0->DMA[_channel].DSR_BCR & (1<<25) == 1<<25); 00174 return (DMA0->DMA[channel].DSR_BCR & 0xFFFFF); 00175 } 00176 00177 /*****************************************************************/ 00178 uint32_t SimpleDMA::remaining(int channel) 00179 { 00180 // note that the BCR register always reads with binary 1110 00181 // (if the configuration is correct) or 1111 (if there's an 00182 // error in the configuration) in bits 23-20, so we need 00183 // to mask these out - only keep bits 19-0 (low-order 20 00184 // bits = 0xFFFFF) 00185 return (DMA0->DMA[channel < 0 ? _channel : channel].DSR_BCR & 0xFFFFF); 00186 } 00187 00188 /*****************************************************************/ 00189 void SimpleDMA::irq_handler(void) 00190 { 00191 DMAMUX0->CHCFG[_channel] = 0; 00192 DMA0->DMA[_channel].DSR_BCR |= DMA_DSR_BCR_DONE_MASK; 00193 _callback.call(); 00194 } 00195 00196 void SimpleDMA::irq_handler0( void ) 00197 { 00198 if (irq_owner[0] != NULL) 00199 irq_owner[0]->irq_handler(); 00200 } 00201 00202 void SimpleDMA::irq_handler1( void ) 00203 { 00204 if (irq_owner[1] != NULL) 00205 irq_owner[1]->irq_handler(); 00206 } 00207 00208 void SimpleDMA::irq_handler2( void ) 00209 { 00210 if (irq_owner[2] != NULL) 00211 irq_owner[2]->irq_handler(); 00212 } 00213 00214 void SimpleDMA::irq_handler3( void ) 00215 { 00216 if (irq_owner[3] != NULL) 00217 irq_owner[3]->irq_handler(); 00218 } 00219 #endif
Generated on Wed Jul 13 2022 03:30:11 by 1.7.2