cancel
Showing results for 
Search instead for 
Did you mean: 

PSoC 5, 3 & 1 MCU

Contributor II

I need to take an ADC reading at a specific point in received data stream from a wireless system.

   

First I dropped an SAR_ADC on the project and tested it worked using this code.

   

ADC_Start();

   

ADC_StartConvert();

   

result = ADC_IsEndConversion(ADC_WAIT_FOR_RESULT);

   

RSSI_Val = ADC_GetResult16(); 

   

Next, I set a flag at the point in data reception I wanted to start sample and when I read the flag in main code I do an ADC sample. Trouble is that I do not have control over the point a packet arrives and therfore the sampling of the ADC is not always occurring when I need it.

   

Would someone have an example how I could start and ADC conversion within the Uart Interrupt routine so that when I get back in main loop the conversion would have been doen at the right time and I can read the value at that point?

   

 

   

Thanks

0 Likes
Reply
13 Replies
Esteemed Contributor

One way of doing it is run SAR continuously, oversampled, and

   

DMA the result to a memory location. Then use packet received flag

   

to simply 'pick" up the result in the memory location.

   

 

   

Or in packet received start adc, wait for its conversion complete. Would the

   

SAR be fast enough to meet your needs ?

   

 

   

How much latency can you tolerate from packet received to ADC result ?

   

 

   

Regards, Dana.

0 Likes
Reply
Honored Contributor II

@Orbitcom,

   

The problem might not be in fast handling of the UART message, but because UART is non-deterministic itself. UART has latency, which can be ~0.1sec. For example you are sending in equal intervals "ADC_start",..."ADC_start",..."ADC_start",... but those packets will not arrive at same intervals, there will be some jitter from packet to packet. Even if ADC sampling starts immediately upon packet received, there will be some time jitter relative to the original 'sent' packet.

   

You need some hard reference to sync ADC sampling. Look at GPS: it has precise global clock TTL each second alongside to slow UART NEMA output.

   

odissey1

0 Likes
Reply
Contributor II

 Dana,

   

The idea of running the ADC continuously and storing to memory location via DMA sounds like a reasonable approach. 

   

I have not used DMA before, is it easy to set up? Also, could I simply copy the register the values are being stored into my variable at the point required inside the Uart interrupt?

   

If si, I could actually save an array of values (one at each received byte) and obtain and average for the entire message.

   

The incoming data rate is 38k Baud. The packets are small (14 bytes fixed length). They arrive at pseudo random intervals with 3-5 packets per second.

   

thanks

0 Likes
Reply
Esteemed Contributor

I have not used DMA before, is it easy to set up?

   

 

   

Yes, there is a wizard in Creator for setup and some good ap notes (Creator also has a number of example projects) -

   

 

   

    

   

         

   

http://www.cypress.com/?rID=37793     AN52705     Getting Started with DMA

   

http://www.cypress.com/?rID=82680     AN84810     PSoC® 3 and PSoC 5LP Advanced DMA Topics

   

http://www.cypress.com/?rID=44335     AN61102 PSoC® 3 and PSoC 5LP - ADC Data Buffering Using DMA

   

http://video.cypress.com/video-library/search/dma/     Videos on DMA

   

https://www.youtube.com/results?search_query=dma+psoc Videos on DMA (some overlap)

   

 

   

 

   

Also, could I simply copy the register the values are being stored into my variable at the point required inside the Uart interrupt?

   

 

   

Yes. You can even have the DMA run a loop where you auto inc the address where bytes are

   

going. You supply a pointer to DMA config for this purpose and an inc value in # bytes depending

   

on what you are transferring. At end of DMA trigger an interrupt and do the average.

   

 

   

Regards, Dana.

0 Likes
Reply
Contributor II

 I set up the DMA using the Wizard but do not appear to be getting ADC results int my memory location.

   

The code generated by the wizard is shown below...

   

The ADC -> EOC is connected to DMA -> DRQ, the hardware request is "derived" (I also tried rising edge).

   

RSSI_Val does not appear to be updated with ADC value.

   

DMA_Chan = DMA_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST, HI16(DMA_SRC_BASE), HI16(DMA_DST_BASE));

   

DMA_TD[0] = CyDmaTdAllocate();

   

CyDmaTdSetConfiguration(DMA_TD[0], 2, DMA_TD[0], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);

   

CyDmaTdSetAddress(DMA_TD[0], LO16((uint32)ADC_SAR_WRK0_PTR), LO16((uint32)RSSI_Val));

   

CyDmaChSetInitialTd(DMA_Chan, DMA_TD[0]);

   

CyDmaChEnable(DMA_Chan, 1);

0 Likes
Reply
Contributor II

 Still cannot get my DMA running for some reason.

   

By the way, what controls conflict when I attempt to read the memory location the DMA is putting data?

0 Likes
Reply
Contributor II

 Still cannot get my DMA running for some reason.

   

By the way, what controls conflict when I attempt to read the memory location the DMA is putting data?

0 Likes
Reply
Esteemed Contributor II

Who told you to use "AUTO_EXEC_NEXT"?

   

This will not wait for ADC data ready.

   

 

   

Bob

0 Likes
Reply
Contributor II

 It was the wonderful wizard of oz. (DMA Wizard configuration starting from page 21 of Doc no. 001-52705 rev 1. Self described as easy to set up the firmware configuration (ideal for a DMA newbie).

   

I followed the documented example but set Auto Next to true and Next TD = 0 (to go back and rerun).

   

What did I miss here?

0 Likes
Reply
Contributor II

 I have a SAR ADC connected to my Analog input pin. The mode is set to free running.

   

The EOC is connected to the "drq" pin of the DMA. The DMA hardware request set to Derived. Then used the wizard again and set number of TD = 1 and select "Loop".

   

I start the ADC in code and also have used code below. The RSSI_Val remains at "0". If I remove the DMA and do a manual sample using ADC API I get the correct values.

   

/* Variable declarations for DMA */

   

/* Move these variable declarations to the top of the function */

   

uint8 DMA_Chan;

   

uint8 DMA_TD[1];

   

 

   

/* DMA Configuration for DMA */

   

#define DMA_BYTES_PER_BURST 2

   

#define DMA_REQUEST_PER_BURST 1

   

#define DMA_SRC_BASE (CYDEV_PERIPH_BASE)

   

#define DMA_DST_BASE (CYDEV_SRAM_BASE)

   
    DMA_Chan = DMA_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST, HI16(DMA_SRC_BASE), HI16(DMA_DST_BASE));   
   

DMA_TD[0] = CyDmaTdAllocate();

   

CyDmaTdSetConfiguration(DMA_TD[0], 2, DMA_TD[0], 0);

   

 CyDmaTdSetAddress(DMA_TD[0], LO16((uint32)ADC_SAR_WRK0_PTR), LO16((uint32)RSSI_Val));

   

 CyDmaChSetInitialTd(DMA_Chan, DMA_TD[0]);

   

 CyDmaChEnable(DMA_Chan, 1);

0 Likes
Reply
Esteemed Contributor II

It would be much easier for me to get hands on your (not-)working project, so I could adapt it to my hardware (-050 board) and test it.

   

Can you just reduce your project to the barest and upload it?

   

 

   

Bob

0 Likes
Reply
Contributor II

 Bob,

   

Cut down project attached.This locks up in main loop.

   

What I need is the ADC obtaining data continuously and poking result via DMA into the "signal Level" variable.

   

The aim is to capture the level sample as close to the specific time in my code possible.

0 Likes
Reply
Contributor II

 Attachment cause gobbly gook on screen and didn't upload for some reason. Here is second attempt to upload it.

0 Likes
Reply