4
\$\begingroup\$

I just received my PIC32 starter kit, and played with the demos. I have never used any higher-end uCs than the 8-bit PICs.

One of the new things to me in the PIC32 is DMA. The starter kit came with demo that uses chained DMA transfers to control the pwms and dim two of the leds.

I tried to experiment adding the third led to the chain, but it didn't work out. I believe it is because I don't know how to chain the three DMA channels.

Basically I am trying to get a chain: DMACh0 -> DMACh1 -> DMAch2 -> DMACh0 -> ...

Here is one of the modified versions (Some stock comments and config cut out to get it smaller):

const unsigned short pwm_duty_cycles[] = {...};
#define ARRAY_SIZE                      (sizeof(pwm_duty_cycles))
#define DMA0                            (0)
#define DMA1                            (1)
#define DMA2                            (2) // Added this line

unsigned char srcSize = ARRAY_SIZE;
unsigned char cellSize = 2;     
unsigned int dstSize = 2;

unsigned short* volatile pDma_0_Dst = (void*) &OC1RS;
unsigned short* volatile pDma_1_Dst = (void*) &OC2RS;  
unsigned short* volatile pDma_2_Dst = (void*) &OC3RS;     // Also added this
const unsigned short* pDmaSrc = pwm_duty_cycles;        

#define SYS_FREQ            (80000000)
#define PWM_PERIOD          (25000)

//  pwm_dma application code
int main(void)
{
    SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

    DmaChnOpen(DMA0, 0, DMA_OPEN_CHAIN_LOW);
    DmaChnOpen(DMA1, 0, DMA_OPEN_CHAIN_HI);
    DmaChnOpen(DMA2, 0, DMA_OPEN_CHAIN_HI);   // Added this line, I'm not sure how to set up the
                                              // chaining. What should be LOW and what should be HIGH


    DmaChnSetEventControl(DMA0, DMA_EV_START_IRQ(_TIMER_4_IRQ));
    DmaChnSetEventControl(DMA1, DMA_EV_START_IRQ(_TIMER_4_IRQ));
    DmaChnSetEventControl(DMA1, DMA_EV_START_IRQ(_TIMER_4_IRQ));   // Added

    DmaChnSetTxfer(DMA0, pDmaSrc, pDma_0_Dst, srcSize, dstSize, cellSize);
    DmaChnSetTxfer(DMA1, pDmaSrc, pDma_1_Dst, srcSize, dstSize, cellSize);
    DmaChnSetTxfer(DMA2, pDmaSrc, pDma_2_Dst, srcSize, dstSize, cellSize); // Added

    OpenOC1(OC_ON | OC_TIMER_MODE16 | OC_TIMER3_SRC | OC_PWM_FAULT_PIN_DISABLE, 0,0);
    OpenOC2(OC_ON | OC_TIMER_MODE16 | OC_TIMER3_SRC | OC_PWM_FAULT_PIN_DISABLE, 0,0);
    OpenOC3(OC_ON | OC_TIMER_MODE16 | OC_TIMER3_SRC | OC_PWM_FAULT_PIN_DISABLE, 0,0); // Added
    OpenTimer3(T3_ON | T3_PS_1_64, PWM_PERIOD);
    OpenTimer4(T4_ON | T4_PS_1_256, 100000);

    DmaChnEnable(DMA0);

    while(1);
}

I think the problem is with setting DMA_OPEN_CHAIN_LOWs and DMA_OPEN_CHAIN_HIs. I assume these HI and LOW mean the channel priorities. These only allow me to specify the next channel with either higher or lower priority. How can I make it jump over a channel (ch2 -> ch0)?

I am using Mplab C32 v2.02. This brings up memories, trying to modify the examples to get one more led blink :)

\$\endgroup\$
1
\$\begingroup\$

The reason is explained in the PIC32MX DMA controller reference manual (page 31-35):

A channel (slave channel) can be chained to an adjacent channel (master channel).

This means you cannot chain 3 DMA channels together.

But to answer your question about how this chaining works, look at page 31-16 in the manual:

CHCHNS: Chain Channel Selection bit(5)

1 = Chain to channel lower in natural priority (CH1 will be enabled by CH2 transfer complete)

0 = Chain to channel higher in natural priority (CH1 will be enabled by CH0 transfer complete)

The channel 0 has the highest priority, and channel 3 the lowest (the Pic32MX360F512L has 4 channels). So setting the first DMA channel to chain in lower order means it gets triggered by channel 1 (in your example).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.