MQX + DMA?

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

MQX + DMA?

Jump to solution
2,204 Views
billnd
Contributor IV

I get the impression that if I want to use DMA with MQX I'll have to go way off piste. Is this assumption correct? If so what is the best way to go about it, presumably there is no docs/an's giving examples?

What I'm trying to do is fire off the ADC from the PDB, then get the ADC to generate a DMA request on completion. I'm fairly sure none of the MQX ADC drivers will support this, so what is the suggested route?

PS on a Kenetis uP if that has any bearing.

Tags (4)
1 Solution
663 Views
DavidS
NXP Employee
NXP Employee

Hi Bill,

MQX is extremely flexible and as the system designer you can literally "to-it-your-way".  So no right or wrong answer.  Just trying to implement the coding as you like.

The option #1 you mention is fine.  Not certain what you mean by outside any MQX command but will guess you mean accessing the peripheral registers directly.  You might also mean that the interrupt(s) will operate outside MQX as well.  This is OK too.

Option #2 is what I recommend starting with and then if the MQX system cannot achieve the timing you need, then implementing direct interrupts (sometimes called Gorilla interrupts) will prempt the MQX RTOS while you service the DMA interrupt.

It all comes down to managing the system how you want.

Regards,

David

View solution in original post

0 Kudos
5 Replies
663 Views
DavidS
NXP Employee
NXP Employee

Hi Billnd,

Please have a look at following appnote (it does have ZIP file with code too).

AN4590 Using DMA to Emulate ADC Flexible Scan Mode on Kinetis K Series

Short Cut to ZIP

The appnotes can be found under the product pages of the device by clicking the Documentation tab.

Regards,

David

663 Views
billnd
Contributor IV

David,

Thanks for your response. I think I may have phrased my question badly, indeed reading it back it does not ask the question that I'm looking to answer. So, I'll give it another go...

I'm planning to use the ADC in a fashion that is not fully supported by MQX, ie linking it to the DMA system. As far as I see it there are two different routes I can take....

1. Use MQX for as much of the ADC work as possible, ie calibration, config (as much as MQX supports) and PDB triggers. But then, outside of any MQX command, alter the ADC to fire off the DMA.

2. Side step MQX completely for all the ADC work, and set it up without using any MQX commands.

My gut feeling is that option 2 is likely to cause least hassle, but option 1 may offer some unknown benefits. Thoughts?

Although in this example I'm being specific about the ADC, I'm really after formulating a general principle regarding using MQX. Should I be aiming to use MQX for as much as possible, or is it better to only use it for things that it supports 100%?

Cheers in advance.

Bill

0 Kudos
664 Views
DavidS
NXP Employee
NXP Employee

Hi Bill,

MQX is extremely flexible and as the system designer you can literally "to-it-your-way".  So no right or wrong answer.  Just trying to implement the coding as you like.

The option #1 you mention is fine.  Not certain what you mean by outside any MQX command but will guess you mean accessing the peripheral registers directly.  You might also mean that the interrupt(s) will operate outside MQX as well.  This is OK too.

Option #2 is what I recommend starting with and then if the MQX system cannot achieve the timing you need, then implementing direct interrupts (sometimes called Gorilla interrupts) will prempt the MQX RTOS while you service the DMA interrupt.

It all comes down to managing the system how you want.

Regards,

David

0 Kudos
663 Views
uabc_mac
Contributor I

HI DAVID

I am trying to configure UART-DMA  yet I cannot do so far.

Could you help me to resolve my problem? I am not sure concerning to interruption value.

In intention to help for better understanding of my problem I divide this message into three sesions.

(A) my Check list.

(B) References

(C) My code.

Thanks for your help in advance.

(A)

1.- UART3 configuration to 9600 bps using TTYD

Uart_serie3 = fopen("ttyd:", BSP_DEFAULT_IO_OPEN_MODE);

            if (Uart_serie3==NULL)

            {

                printf("ERROR ");

            }

            else{

                write(Uart_serie3,(pointer)"Ready 3",7);

               fflush(Uart_serie3);

            }

2.- Interrupt-function asociation.

    

       _int_install_isr(32, dam0_isr,buffer_TUART3.buffer);

      interrupcion 32 es del DMA

  

   I tried using following configuration but does not work

      _int_install_isr(INT_UART3_RX_TX, dam0_isr,buffer_TUART3.buffer);

3.- I made the TCD configuration followin intructions on AN2998-1.pdf page 10 table 4.20, as well as two references from towergeeks

4.- To activate the configuration I did the following.

    configure_TCD();

    Enable_channel_0_1(); transmission reception channels ON

    DMA_on(1); CHANNEL 1 ON

   

(B) REFERENCES

https://community.freescale.com/thread/117204

https://community.freescale.com/message/106758#106758

AN2998-1.pdf PAGE 10 TABLE 4.20 transfer control descriptors

Document Number: K60P100M100SF2RM Rev. 6, Nov 2011

(C)

#include "main.h"

//BUFFERS for Tx and Rx in UART3 to be used by DMA

struct _uart_buf

{

  int index;

  char buffer[64];

} buffer_RUART3,buffer_TUART3;

//pointer to UART 5 and 3

MQX_FILE_PTR Uart_serie5=NULL;

MQX_FILE_PTR Uart_serie3=NULL;

/* function for UART-DMA interruption*/

void dam0_isr(pointer user_DMAisr_ptr)

{

  static unsigned char cnt=0;

  DMA_INT = 0x1; // clear dma int flag

  cnt++;

  memset(buffer_TUART3.buffer,cnt,64);

  DMA_TCD0_SADDR = (unsigned long)&buffer_TUART3.buffer[0];

  DMA_ERQ |= (1 << 0);//

  DMA_TCD1_DADDR = (unsigned long)&buffer_RUART3.buffer[0];

  DMA_ERQ |= (1 << 1);//

}

/* turn on channels DMAmux 0 and 1 Tx and Rx for UART3*/

void Enable_channel_0_1(void)

{

    /* Configure DMAMux for Channel 0 */

    DMAMUX_CHCFG0 = 9; //receive UART3_TX  

    DMAMUX_CHCFG0 |= DMAMUX_CHCFG_ENBL_MASK;//Enable DMA channel

    DMA_ERQ |= (1 << 0);// inicia START 

  

    /* Configure DMAMux for Channel 1 */

    DMAMUX_CHCFG1 = 8; // transmitte UART3_TX  

    DMAMUX_CHCFG1 |= DMAMUX_CHCFG_ENBL_MASK;//Enable DMA channel

    DMA_ERQ |= (1 << 1);// inicia START     

   

}

/*  TCD configuration based on AN2998-1.pdf page 10 table 4.20 transfer control descriptors

* and the Document Number: K60P100M100SF2RM Rev. 6, Nov 2011 */

void configure_TCD (void)

{

    DMAMUX_CHCFG0 = 0; //channel 0 turn off

    /* Configure DMA Channel 0 TCD */

    DMA_TCD0_SADDR = ((uint_32)&UART3_D);/* data  UART3_D, 0x4006D007 UART3 address*/

  

    DMA_TCD0_ATTR = (DMA_ATTR_SMOD(0x0) /* Source Modulo, feature disabled */

            | DMA_ATTR_SSIZE(0x0) /* Source Size = 0x0 -> 8-bit transfers */

            | DMA_ATTR_DMOD(0x0)); /* Destination Modulo, feature disabled */

    //        | DMA_ATTR_DSIZE=(0x0)); /* Destination Size = 0x2 -> 32-bit transfers */

    DMA_TCD0_SOFF = 0; /* Source addr offset = 0x0, el incremento lo dejo a cero porque la direccion es fija */

  

    DMA_TCD0_NBYTES_MLNO = 0x4; /* Transfer 4 bytes per channel activation */

    DMA_TCD0_SLAST = DMA_SLAST(0x0); /* Do not adjust SADDR upon channel completion */

    DMA_TCD0_DADDR = ((uint_32)&buffer_RUART3.buffer[0]); /* Destination Address = BUFFER DE RECEPCION */

  

    DMA_TCD1_CITER_ELINKNO = 0;

    DMA_TCD1_CITER_ELINKNO = 0x1; /* Current Iter Count -> 1 "NBYTES" transfer */

    DMA_TCD1_DOFF = 0x1; /* Destination addr offset = 0x1, AQUI SI INCREMENTO PARA QUE LO ALMACENE EN EL BUFFER DE RECEPCION */

    DMA_TCD1_DLASTSGA = 0x0; /* Do not adjust DADDR upon channel completion */

    DMA_TCD1_BITER_ELINKNO = 0;

    DMA_TCD1_BITER_ELINKNO = 0x1; /* TCD Beginning Minor Loop Link, Major Loop Count (Channel Linking Disabled) */

  

    DMA_TCD1_CSR = 0;

    DMA_TCD1_CSR |= DMA_CSR_INTMAJOR_MASK; /* Enable an interrupt when major iteration count completes.*/

    DMA_TCD1_CSR |= DMA_CSR_DREQ_MASK; /* If this bit is set when the channel completes a major loop, the eDMA clears the

    corresponding DMAERQ, disabling the transfer request.*/

    DMA_TCD1_CSR |= 1 << 255; // ACTIVA EL START

    NVICISER0 |= 1 << 0 ;// enable interrupt NVICISERn = 1 << m, where n = 0/32, m = 0% 32 dma interrupt 32

    NVICICPR0 |= 1 << 0;  

    DMAMUX_CHCFG1 = 0;

    /* Configure DMA Channel 1 TCD */

    DMA_TCD1_SADDR = ((uint_32)&buffer_TUART3.buffer[0]);/* Source Addr = address of command var */

  

    DMA_TCD1_ATTR = (DMA_ATTR_SMOD(0x0) /* Source Modulo, feature disabled */

            | DMA_ATTR_SSIZE(0x0) /* Source Size = 0x0 -> 8-bit transfers */

            | DMA_ATTR_DMOD(0x0)); /* Destination Modulo, feature disabled */

   //         | DMA_ATTR_DSIZE=(0x2)); /* Destination Size = 0x2 -> 32-bit transfers */

   DMA_TCD1_SOFF = 1; /* Source addr offset = 0x1, increment */

    DMA_TCD1_NBYTES_MLNO = 0x4; /* Transfer 4 bytes per channel activation */

    DMA_TCD1_SLAST = 0x0; /* Do not adjust SADDR upon channel completion */

    DMA_TCD1_DADDR = ((uint_32)&UART3_D);/* Dest Addr =  UART3_D Command Word Register 0x4006D007*/

  

    DMA_TCD1_CITER_ELINKNO = 0;

    DMA_TCD1_CITER_ELINKNO = 0x1; /* Current Iter Count -> 1 "NBYTES" transfer */

    DMA_TCD1_DOFF = 0x1; /* Destination addr offset = 0x1, increment */

    DMA_TCD1_DLASTSGA = 0x0; /* Do not adjust DADDR upon channel completion */

    DMA_TCD1_BITER_ELINKNO = 0;

    DMA_TCD1_BITER_ELINKNO = 0x1; /* TCD Beginning Minor Loop Link, Major Loop Count (Channel Linking Disabled) */

   

  

    DMA_TCD1_CSR = 0;

    DMA_TCD1_CSR |= DMA_CSR_INTMAJOR_MASK;

    DMA_TCD1_CSR |= DMA_CSR_DREQ_MASK;

    DMA_TCD1_CSR |= 1 << 255;

    NVICISER0 |= 1 << 0 ;// enable interrupt NVICISERn = 1 << m, where n = 0/32, m = 0% 32 dma interrupt 32

    NVICICPR0 |= 1 << 0;  

}

void DMA_off(int DMA_CHn)

{

      DMA_ERQ &= ~(1 << DMA_CHn);    /* stop; The ERQ register provides a bit map for the 16 implemented channels to enable the request signal for each channel.  */

}

void DMA_on(int DMA_CHn)

{

    DMA_ERQ |= (1 << DMA_CHn); /* start The ERQ register provides a bit map for the 16 implemented channels to enable the request signal for each channel.  */

}

/* Parametros tomados de recomendaciones de twr geeks

* https://community.freescale.com/thread/117204

* https://community.freescale.com/message/106758#106758 */

void UART_config()

{

    /* no configurar la UART en modo interrupcion !!!! */

    UART3_C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);

    UART3_C5 &= ~(UART_C5_TDMAS_MASK | UART_C5_RDMAS_MASK);

    UART3_C5 |= UART_C5_TDMAS_MASK;

    UART3_C5 |= UART_C5_RDMAS_MASK;

    UART3_C2 = (1 << 7) | (1 << 5) | (1 << 2) ;// allow income, interrupt, it allows the receiver to

    UART3_C5 = (1 << 7) | (1 << 5) ;// allow the recipient, hair interrupt generates a DMA request

    UART3_C1 |= 1 << 7 ;// use loopback mode

    UART3_C2 |= UART_C2_TE_MASK; //| UART_C2_RE_MASK);

   

    SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;

    SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;

  

    // Set FIFO water marks (not used in default 'legacy' port configuration)

    UART3_TWFIFO = UART_TWFIFO_TXWATER(0);

    UART3_RWFIFO = UART_RWFIFO_RXWATER(1);

}

void DMA_config()

{

    configure_TCD();

    Enable_channel_0_1();

}

TASK_TEMPLATE_STRUCT MQX_template_list[] =

{

/*  Task number, Entry point, Stack, Pri, String, Auto? */

   {MAIN_TASK,   Main_task,   2000,  9,   "main", MQX_AUTO_START_TASK},

   {0,           0,           0,     0,   0,      0,                 }

};

/*TASK*-----------------------------------------------------------------

*

* Function Name  : Main_task

* Comments       :

*    This task initializes MFS and starts SHELL.

*

*END------------------------------------------------------------------*/

void Main_task(uint_32 initial_data)

{

        short int i;

        //MY_ISR_STRUCT_PTR  isr_ptr=NULL;

       

            rtcs_init();

            Uart_serie3 = fopen("ttyd:", BSP_DEFAULT_IO_OPEN_MODE);

            if (Uart_serie3==NULL)

            {

                printf("ERROR no se pudo abrir el dispositivo serial 3");

            }

            else{

                write(Uart_serie3,(pointer)"Ready 3",7);

               fflush(Uart_serie3);

            }

           Uart_serie5 = fopen("ittyf:", BSP_DEFAULT_IO_OPEN_MODE);

            if (Uart_serie5==NULL)

            {

                printf("ERROR no se pudo abrir el dispositivo serial 5");

            }

            else{

                 write(Uart_serie5,(pointer)"Ready 5",7);

             fflush(Uart_serie5);

            }

           

         

            _int_install_isr(32, dam0_isr,buffer_TUART3.buffer);

           

            UART_config();

            DMA_config();

            DMA_on(1);

           

            for (i = 0; i <64; i ++)

            {

                buffer_TUART3.buffer[i] = 'A';

            } 

            buffer_TUART3.index = 1;

            buffer_RUART3.index = 0;

            UART3_C2 |= 1 << 3; /* Activa la recepcion de mensajes */

              fflush(Uart_serie3);

          for (;;)

       {

               _time_delay_ticks(1000);

               for (i = 0; i <64; i ++)

                 {

                   write(Uart_serie3,(pointer)&buffer_TUART3.buffer[i],1);

                 }

               write(Uart_serie3,"\r\n",2);

                

       }

        

          fflush(Uart_serie3);

          close(Uart_serie3);

          fflush(Uart_serie5);

          close(Uart_serie5);

          DMA_off(0);

          DMA_off(1);

       _mqx_exit(0);

}

0 Kudos
663 Views
macl
Senior Contributor I

Hi,

Should start to see a bit more DMA support in a few MQX drivers in future releases.  Keep an eye out for the releases towards the second half of the year.  In the meantime, as David mentioned, it is very flexible and allows for DMA support to be added and customized.

Thanks,

MacL