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 Mike R

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SimpleDMA_KL25_46.cpp Source File

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