Using DMA to emulate ADC - AN4590

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

Using DMA to emulate ADC - AN4590

Jump to solution
4,880 Views
andreag
Contributor II

Hello,

this is a very interesting appnote and I would like to use something very similar in a motor drive application (3-phase inverter) using my FRDM-KL25Z.

Here are a few of the questions on the ADC peripheral usage I am struggling with at the moment. I hope someone can provide some more insight…

  1. Could I get the code related to AN4590? I could not find it online, and in the appnote only the code for the DMA is there.  I would like to take a look at the ADC configuration code…
  2. What I would like to achieve is something similar to AN4590 with the following differences:
    1. Use LPTMR0 trigger instead of PDB Trigger1 (p.4)
    2. Go through all the ADC sequence without further HW triggers
    3. Next ADC sequence will be started by the next LPTMR0 trigger
    4. Use circular buffer to store results (eg 6ADC channels x 6 values = 36 conversion circular buffer)


Thanks!

Andre

1 Solution
2,757 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

From your attached code, I regenerate the DMA address decrease phenomenon.

When I modify DMA Channel 0 DMA_DCR0[SMOD] value with 0x0 buffer disabled, the DMA source address SAR0 will increase as expected.

The root cause is if using the buffer, it need the source/destination address should be align with dedicated buffer size, otherwise it cause the address error.

For example, if SMOD set with 0x1 (16 bytes), the source/destination address low 4-bit should be 0.

Wish it helps.

with regards,

Ma Hui

View solution in original post

0 Kudos
23 Replies
2,655 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Thank Jose's answer.

About question 2 b-d, I think it need to use ADC module with hardware trigger single mode. That means ADC module can not use only one hardware tigger with ADC conversion continue mode, otherwise during the DMA channel transfer ADC conversion result, the ADC module will start the next conversion. That could cause problem. It can use circular buffer to store ADC conversion result.
Please refer attached project about put ADC conversion result to a circle buffer.
Wish it helps.

2,655 Views
andreag
Contributor II

Hello,

thanks you for the answers.

So here is how I am thinking to solve the problem (requires 3 DMA channels)

  1. Coonfigure ADC for SW trigger, so writing ADC_SC1 will trigger a conversion
  2. Use a TPM DMA requset to load the first channel in ADC_SC1
  3. Use ADC DMA to trasnfer the result to a buffer (similar to the appnote)
  4. Use a linked DMA channel to load the next channel in ADC_SC1
  5. the last channel loaded will be a Atop_channel
  6. everything restarts with the next TPM DMA trasnfer on the first channel

How does this sound?

On the appnote code, could you explain to me this line?

DMAMUX_CHCFG0       = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x36);   //DMA source DMA Mux

This channel is supposed to be linked to DMA channel 1, but I don't thin sourse 36 is the other DMA channel. IN the KL25Z there are channels 60-63 called generically DMA MUX. Should I use one of these? Any difference between them?

Thanks for the help!

Andre

2,655 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Andre,

I check your ADC scan process sounds reasonable. When the DMA channel load the next channel to ADC_SC1 will software trigger a new ADC conversion.

About the application note code, the linked channel DMA request, there with no restricted requirement. The linked DMA channel will start transfer when link condition become true (whatever related DMA request status). You can select unused DMA trigger source of KL25 for DMA Channel 0.

Wish it helps.

0 Kudos
2,655 Views
andreag
Contributor II

HI Hui,

thanks for the info.

Just to be sure I assigned ch0 to one of the always on channels in the DMAMUX...

I have 2 more questions that came up while configuring this peripheral:

1/ my understanding is that on the Kinetis L it is not possible to specify the destination address reload after a major loop finishes like this line in the example on p.5 of AN4590:

DMA_TDC1_DLASTSGA = -24;

So if I set up my DMA channel to transfer data (cycle steal) to a destination circular buffer, what happens after the BCR=0? I would want the destination to work as a circular buffer, so start overwriting the data from the first position. How can I implement this without the above feature? Do I need to trigger an IRQ and write the initial destination address? Or will the DMA circular buffer handle it in

2/ The other question is relative to DMA Control Register (DMA_DCRn) - EINT: "Enable interrupt on completion of transfer"

Does this interrupt happen after each data transfer, or after the end of the block trasnfer (BCR=0)

Thanks for your help!!!

0 Kudos
2,655 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Andrea,

As Jose mentioned:

1> If the BCR = 0, even there with DMA trigger happens, DMA module stop the DMA transfer. If customer is using circular buffer, the DMA module will automatically handler the destination address back to the circular buffer first position.

2> The DMA_DCRn [EINT] interrupt happens after the end of the block transfer (BCR = 0).

Wish it helps.

B.R.

Ma Hui

0 Kudos
2,655 Views
andreag
Contributor II

Thanks guys!

I think this should work then..

In regards to the channel configured as the linked channel, which one of these 2 bits enables the DMA (so which one should I set?):

  1. DCR(ERQ]
  2. DCR[START]

I did connect it to an always on DMAMUX channel, so maybe (1) is correct. But what would happen if I use (1) and I connect it to an unused channel like you suggested?

Thanks!

0 Kudos
2,655 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

If the linked DMA channel connect with an always on DMAMUX channel, there will be ok to set DCR[ERQ], while if DCR[START] is set, which will start DMA transfer. So, my suggestion to just set DCR[ERQ] bit.

And if the linked DMA channel connect with unused channel source, it also could start DMA transfer with Link condition become true.

Wish it helps.

0 Kudos
2,655 Views
andreag
Contributor II

HI Hui,

this is pretty confusing!

If I set the linked channel to an always ON DMAMUX channel, wouldn't setting DCR[ERQ] make the DMA transfer data continuously?

Thanks!

0 Kudos
2,655 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Andrea,

Without set DCR[ERQ] bit, the always ON DMAMUX channel also could make DMA transfer data continously when just software start DMA transfer.

Wish it helps.

B.R.

Ma Hui

0 Kudos
2,655 Views
andreag
Contributor II

OK, so I've been working on several things but this part is still not working.

I've setup 2 DMA as described above and I have 2 simple IRQ to reload them:

/*----------------------------------------------------------------------------

  DMA1_Handler: reloads the destination buffer

*----------------------------------------------------------------------------*/

void DMA1_IRQHandler(void) {

    DMA0->DMA[1].DSR_BCR |= DMA_DSR_BCR_DONE_MASK ;                /* clear by writing 1 */

    DMA0->DMA[1].DAR = (uint32_t) &uiADC_buffer[0];                /* destination: ADC results circular buffer */

    DMA0->DMA[1].DSR_BCR = DMA_DSR_BCR_BCR(uiDMA1_BCR);   

}

/*----------------------------------------------------------------------------

  DMA0_Handler: reloads list of ADC channels' SC1

*----------------------------------------------------------------------------*/

void DMA0_IRQHandler(void) {

    DMA0->DMA[0].DSR_BCR |= DMA_DSR_BCR_DONE_MASK ;                /* clear by writing 1 */

    DMA0->DMA[0].SAR = (uint32_t) &(uiADCcfg_SC1[0]) ;         /* next TPM IRQ will start DMA0 which will start fomr ch0 */

    DMA0->DMA[0].DSR_BCR = DMA_DSR_BCR_BCR(uiDMA0_BCR);

}

After configuration I get:

BCR1=30

DAR1=0x1FFFF0F4

and

BCR0=1C

SAR0= 0x1FFFF2F4

after the first ADC I set up and IRQ to monitor what happens and I would expect the counters to decrement by and the addresses to increment by 4 (32bit=4bytes).

However the address actually have decremented!

DAR1=0x1FFFF010

SAR0=0x1FFFF2D0

I'm at a loss...any ideas?

Thanks!

0 Kudos
2,655 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Could you send me your KL25 DMA related code? I will check on my FRDM-KL25Z board.

0 Kudos
2,655 Views
andreag
Contributor II

Hi,

I'm attaching a Keil project with only the configuration part of my project. It compiles on my setup so hopefully it should be easy to get it up and running on your system.

Thanks!

0 Kudos
2,653 Views
cfernandes
Contributor I

Hi Hui_Ma

I am trying to develop an application requiring uart0 tx/rx with DMA. I am new in code warrior and I am using KL26Z.

I have tried your example, changed the CPU however it is not working,

Error:

c:/freescale/cw mcu v10.6/cross_tools/arm-none-eabi-gcc-4_7_3/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/bin/ld.exe: section .testdata0 loaded at [00002198,00002217] overlaps section .romp loaded at [00002198,000021af]

collect2.exe: error: ld returned 1 exit status

mingw32-make: *** [KL25_ADC_DMA.elf] Error 1'

I would be very grateful if you could give me some hints.

Thank you in advance!

0 Kudos
2,653 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

Sorry for the delay reply.

I would recommend customer to download KL26 sample code from below link:

http://cache.freescale.com/files/32bit/software/FRDM-KL26Z_SC.exe

It includes [uart0_dma] demo for IAR IDE software, while customer can refer that software code.

Wish it helps.


Have a great day,
best regards,

Ma Hui

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
2,758 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

From your attached code, I regenerate the DMA address decrease phenomenon.

When I modify DMA Channel 0 DMA_DCR0[SMOD] value with 0x0 buffer disabled, the DMA source address SAR0 will increase as expected.

The root cause is if using the buffer, it need the source/destination address should be align with dedicated buffer size, otherwise it cause the address error.

For example, if SMOD set with 0x1 (16 bytes), the source/destination address low 4-bit should be 0.

Wish it helps.

with regards,

Ma Hui

0 Kudos
2,655 Views
andreag
Contributor II

Hi Hui,

I'm a little confused:

so I can increment Source (or Destination address) automatically without using buffer (SMOD=0x0)? and just reload the first address in the DAM_IRQ like I do now?

If so, what is the purpose of the circular buffer? And if I want to use it, how can I force the address of both source/destination to have the lower 4bits = 0?

Thanks!

0 Kudos
2,655 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

About how to use Keil to place variable at dedicated address,  please check below link:

ARM: LOCATING VARIABLES AT ABSOLUTE MEMORY ADDRESSES

Or

Compiler Reference Guide: __attribute__((at(address))) variable attribute

I tested it, which works.

Wish it helps.

0 Kudos
2,655 Views
andreag
Contributor II

Hi Hui,

thank you for the references.

However from your previous post I had implied that it was possible to achieve the results I wanted to without using a circular buffer.

Is this correct?

Thanks!

0 Kudos
2,655 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Yes, you are right. Without using a circular buffer, you still could get same result with your code (in DMA interrupt service routine, the source/destination address will be refresh to initialized address.)

Best Regards,

Ma Hui

0 Kudos
2,653 Views
andreag
Contributor II

Hi Hui,

very interesting!

Just for my information, if I wanted to use the circular buffer:

1/ how would I configure BCR: =0, or = size of buffer?

2/ would I still need to use an IRQ, or would the DMA keep going through the circular buffer?

In my case I would like the source of the ADC to run only once, so I don't really need a circular buffer there.

However for the ADC the results it would be great if they could just fill a circular buffer continuously without any intervention (not even an IRQ)

Thanks!

0 Kudos