Problem with PIT triggered DMA ...

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problem with PIT triggered DMA ...

Jump to solution
1,125 Views
q1220200
Contributor III

Hello,

Working with a FRDM-KL25Z board (MKL25Z128VLK4 mcu) and mostly just CMSIS with some boilerplate code from Freescale.

 

What I'm wanting to achieve right now is this:

  1. PIT Timer triggers a single (32bit) DMA memory to memory transfer
  2. That transfer causes the toggling of a GPIO pin

The goal here is to achieve a periodic toggling of a GPIO pin with interrupting the main loop or requiring an interrupt handler to be called. In other words, a blinky LED using just the PIT, DMA and GPIO ... no CPU, no interrupt handlers.

 

 I've no problem getting the PIT timer going. But right now, I can't seem to get the DMA transfer to happen as a result of the PIT timer expiring.

 

Here's a sample of the source code (just using CMSIS and some other boilerplate code from Freescale not shown here):

 

#define LED1 7
const uint32_t LED1_DMA = (1UL << LED1);


// Configure clock for PORTC, DMA Multiplexer, DMA & PIT
SIM->SCGC5 |= SIM_SCGC5_PORTC(1);
SIM->SCGC6 |= SIM_SCGC6_DMAMUX(1) | SIM_SCGC6_PIT(1);
SIM->SCGC7 |= SIM_SCGC7_DMA(1);

 

// Disable DMAMUX channel and PIT timer
DMAMUX0->CHCFG[0] = 0;
PIT->CHANNEL[0].TCTRL &= ~PIT_TCTRL_TEN(1);

 

// Configure DMA Source and Destination addresses
DMA0->DMA[0].SAR = (uint32_t)&LED1_DMA;
DMA0->DMA[0].DAR = (uint32_t)&PTC->PTOR;
DMA0->DMA[0].DCR = DMA_DCR_ERQ(1) | DMA_DCR_CS(1);

 

// Configure PIT
PIT->CHANNEL[0].LDVAL = SystemCoreClock - 1; // 47999999 or one second
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN(1) | PIT_TCTRL_TIE(1);
PIT->MCR = 0; /* Module enabled, don't freeze in debug */

// Enable DMAMUX0 Channel 0, always on and triggered
DMAMUX0->CHCFG[0] |= 60 | DMAMUX_CHCFG_ENBL(1) | DMAMUX_CHCFG_TRIG(1);

 

/* Set Port C Pin 7 to GPIO module */
PORTC->PCR[LED1] &= ~PORT_PCR_MUX_MASK; /* Clear MUX bits */
PORTC->PCR[LED1] |= PORT_PCR_MUX(1); /* Enable pin 7 for GPIO */
PTC->PDDR |= (1UL << LED1); /* Set pin 7 to output */
PTC->PCOR |= (1UL << LED1); /* Set pin 7 low */

 

My understanding is that PIT timer should triggering a DMA transfer of a single 32bit word, as configure, by this stage and that resulting in a GPIO pin toggling (blinking LED) once per second. The PIT is going, but the DMA module is doing nothing.

 

Any assistance would be greatly appreciated.

 

Regards,

 

Paul Swanson

0 Kudos
1 Solution
1,012 Views
q1220200
Contributor III

Not to worry, I solved it!

(With the help of an excellent book, thank you Alexander Dean Textbooks - Efficient Embedded Systems Design and Programming – Arm )

Here's the solution for posterity's sake, how to toggle a GPIO pin using only PIT, DMA & GPIO. The IRQ handlers are necessary but only serve to prepare the prepare the modules for each subsequent event:

#define LED1 7
const uint32_t LED1_DMA = (1UL << LED1);
uint32_t foo = 0;


void PIT_IRQHandler(void)
{
   PIT->CHANNEL[0].TFLG |= PIT_TFLG_TIF(0);
}
void DMA0_IRQHandler(void)
{
   DMA0->DMA[0].DSR_BCR |= DMA_DSR_BCR_DONE_MASK;
   DMA0->DMA[0].SAR = (uint32_t)&LED1_DMA;
   DMA0->DMA[0].DAR = (uint32_t)&PTC->PTOR;
   DMA0->DMA[0].DSR_BCR = DMA_DSR_BCR_BCR(4);
   DMA0->DMA[0].DSR_BCR &= ~DMA_DSR_BCR_DONE_MASK;
   DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_ENBL(1);
}

/* The following is inside the main() * and implies board initialisation and loop etc */


// Configure clock for PORTC, DMA Multiplexer, DMA & PIT
SIM->SCGC5 |= SIM_SCGC5_PORTC(1);
SIM->SCGC6 |= SIM_SCGC6_DMAMUX(1) | SIM_SCGC6_PIT(1);
SIM->SCGC7 |= SIM_SCGC7_DMA(1);

/* Set Port C Pin 7 to GPIO module */
PORTC->PCR[LED1] &= ~PORT_PCR_MUX_MASK; /* Clear MUX bits */
PORTC->PCR[LED1] |= PORT_PCR_MUX(1); /* Enable pin 7 for GPIO */
PTC->PDDR |= (1UL << LED1); /* Set pin 7 to output */
PTC->PCOR |= (1UL << LED1); /* Set pin 7 low */

// Disable DMAMUX channel and PIT timer
DMAMUX0->CHCFG[0] = 0;
PIT->CHANNEL[0].TCTRL &= ~PIT_TCTRL_TEN(1);

// Configure DMA Source and Destination addresses
DMA0->DMA[0].DCR = DMA_DCR_ERQ(1) | DMA_DCR_CS(1) | DMA_DCR_EINT(1);

// Configure PIT
PIT->CHANNEL[0].LDVAL = SystemCoreClock - 1; // 47999999 or one second
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN(1) | PIT_TCTRL_TIE(1);
PIT->MCR = 0; /* Module enabled, don't freeze in debug */

// Enable DMAMUX0 Channel 0, always on and triggered
DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_TRIG(1);

/* Set up interrupt controller */
NVIC_SetPriority(PIT_IRQn, 2);
NVIC_ClearPendingIRQ(PIT_IRQn);
NVIC_EnableIRQ(PIT_IRQn);

NVIC_SetPriority(DMA0_IRQn, 0);
NVIC_ClearPendingIRQ(DMA0_IRQn);
NVIC_EnableIRQ(DMA0_IRQn);

DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_SOURCE(60);

DMA0->DMA[0].SAR = (uint32_t)&LED1_DMA;
DMA0->DMA[0].DAR = (uint32_t)&PTC->PTOR;
DMA0->DMA[0].DSR_BCR = DMA_DSR_BCR_BCR(4);
DMA0->DMA[0].DSR_BCR &= ~DMA_DSR_BCR_DONE_MASK;

DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_ENBL(1);

/* LED toggles off and on once a second from this point on */

View solution in original post

0 Kudos
1 Reply
1,013 Views
q1220200
Contributor III

Not to worry, I solved it!

(With the help of an excellent book, thank you Alexander Dean Textbooks - Efficient Embedded Systems Design and Programming – Arm )

Here's the solution for posterity's sake, how to toggle a GPIO pin using only PIT, DMA & GPIO. The IRQ handlers are necessary but only serve to prepare the prepare the modules for each subsequent event:

#define LED1 7
const uint32_t LED1_DMA = (1UL << LED1);
uint32_t foo = 0;


void PIT_IRQHandler(void)
{
   PIT->CHANNEL[0].TFLG |= PIT_TFLG_TIF(0);
}
void DMA0_IRQHandler(void)
{
   DMA0->DMA[0].DSR_BCR |= DMA_DSR_BCR_DONE_MASK;
   DMA0->DMA[0].SAR = (uint32_t)&LED1_DMA;
   DMA0->DMA[0].DAR = (uint32_t)&PTC->PTOR;
   DMA0->DMA[0].DSR_BCR = DMA_DSR_BCR_BCR(4);
   DMA0->DMA[0].DSR_BCR &= ~DMA_DSR_BCR_DONE_MASK;
   DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_ENBL(1);
}

/* The following is inside the main() * and implies board initialisation and loop etc */


// Configure clock for PORTC, DMA Multiplexer, DMA & PIT
SIM->SCGC5 |= SIM_SCGC5_PORTC(1);
SIM->SCGC6 |= SIM_SCGC6_DMAMUX(1) | SIM_SCGC6_PIT(1);
SIM->SCGC7 |= SIM_SCGC7_DMA(1);

/* Set Port C Pin 7 to GPIO module */
PORTC->PCR[LED1] &= ~PORT_PCR_MUX_MASK; /* Clear MUX bits */
PORTC->PCR[LED1] |= PORT_PCR_MUX(1); /* Enable pin 7 for GPIO */
PTC->PDDR |= (1UL << LED1); /* Set pin 7 to output */
PTC->PCOR |= (1UL << LED1); /* Set pin 7 low */

// Disable DMAMUX channel and PIT timer
DMAMUX0->CHCFG[0] = 0;
PIT->CHANNEL[0].TCTRL &= ~PIT_TCTRL_TEN(1);

// Configure DMA Source and Destination addresses
DMA0->DMA[0].DCR = DMA_DCR_ERQ(1) | DMA_DCR_CS(1) | DMA_DCR_EINT(1);

// Configure PIT
PIT->CHANNEL[0].LDVAL = SystemCoreClock - 1; // 47999999 or one second
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN(1) | PIT_TCTRL_TIE(1);
PIT->MCR = 0; /* Module enabled, don't freeze in debug */

// Enable DMAMUX0 Channel 0, always on and triggered
DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_TRIG(1);

/* Set up interrupt controller */
NVIC_SetPriority(PIT_IRQn, 2);
NVIC_ClearPendingIRQ(PIT_IRQn);
NVIC_EnableIRQ(PIT_IRQn);

NVIC_SetPriority(DMA0_IRQn, 0);
NVIC_ClearPendingIRQ(DMA0_IRQn);
NVIC_EnableIRQ(DMA0_IRQn);

DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_SOURCE(60);

DMA0->DMA[0].SAR = (uint32_t)&LED1_DMA;
DMA0->DMA[0].DAR = (uint32_t)&PTC->PTOR;
DMA0->DMA[0].DSR_BCR = DMA_DSR_BCR_BCR(4);
DMA0->DMA[0].DSR_BCR &= ~DMA_DSR_BCR_DONE_MASK;

DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_ENBL(1);

/* LED toggles off and on once a second from this point on */

0 Kudos