Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Problem with ADC using DMA in dspic33f

Status
Not open for further replies.

Honey15

New Member
Hi everyone,

I'm a new programmer of dspic33f and facing issues with getting ADC working with DMA. I'm using dspic33fj128mc804 and need to read 8 analog readings using DMA. The problem is that I can see the values on putty but however the values are not always correct. For example: in case of just printing one readings I get the below output.

Can anyone please help me with this , please?

Below is my code and the screenshot of the output.

Thanks much in advance!

<code>
  1. /*=======================================================================
  2. Initialize ADC
  3. ========================================================================= */

  4. void initadc(void)
  5. {
  6. AD1CON1bits.FORM = 0; // Data Output Format: Integer
  7. AD1CON1bits.SSRC = 7; // Sample Clock Source: GP Timer starts conversion
  8. AD1CON1bits.ASAM = 1; // ADC Sample Control: Sampling begins immediately after conversion
  9. AD1CON1bits.AD12B = 1; // 12-bit ADC operation

  10. AD1CON2bits.CSCNA = 1; // Scan Input Selections for CH0+ during Sample A bit
  11. AD1CON2bits.CHPS = 0; // Converts CH0

  12. AD1CON3bits.ADRC = 0; // ADC Clock is derived from Systems Clock
  13. AD1CON3bits.ADCS = 65; // ADC Conversion Clock Tad=Tcy*(ADCS+1)= (1/40M)*64 = 1.6us (625Khz)
  14. // ADC Conversion Time for 10-bit Tc=12*Tab = 19.2us

  15. AD1CON1bits.ADDMABM = 0; // DMA buffers are built in scatter/gather mode
  16. AD1CON2bits.SMPI = (NUM_CHS2SCAN-1); // 8 ADC Channel is scanned
  17. AD1CON4bits.DMABL = 3; // Each buffer contains 8 words

  18. //AD1CSSH/AD1CSSL: A/D Input Scan Selection Register
  19. AD1CSSLbits.CSS0=1; // Enable AN4 for channel scan
  20. AD1CSSLbits.CSS1=1; // Enable AN5 for channel scan
  21. AD1CSSLbits.CSS2=1; // Enable AN10 for channel scan
  22. AD1CSSLbits.CSS3=1; // Enable AN13 for channel scan
  23. AD1CSSLbits.CSS4=1;
  24. AD1CSSLbits.CSS5=1;
  25. AD1CSSLbits.CSS6=1;
  26. AD1CSSLbits.CSS7=1;
  27. IFS0bits.AD1IF = 0; // Clear the A/D interrupt flag bit
  28. IEC0bits.AD1IE = 0; // Do Not Enable A/D interrupt
  29. AD1CON1bits.ADON = 1; // Turn on the A/D converter

  30. }


  31. /*=======================================================================
  32. Initialize DMA
  33. ========================================================================= */

  34. void initDma0(void)
  35. {
  36. DMA0CONbits.AMODE = 2; // Configure DMA for Peripheral indirect mode
  37. DMA0CONbits.MODE = 2; // Configure DMA for Continuous Ping-Pong mode
  38. DMA0PAD=(int)&ADC1BUF0;
  39. DMA0CNT = (SAMP_BUFF_SIZE*NUM_CHS2SCAN)-1;
  40. DMA0REQ = 13; // Select ADC1 as DMA Request source

  41. DMA0STA = __builtin_dmaoffset(&BufferA);

  42. IFS0bits.DMA0IF = 0; //Clear the DMA interrupt flag bit
  43. IEC0bits.DMA0IE = 1; //Set the DMA interrupt enable bit

  44. DMA0CONbits.CHEN=1; // Enable DMA

  45. }

  46. unsigned int DmaBuffer = 0;

  47. /*=============================================================================
  48. _DMA0Interrupt(): ISR name is chosen from the device linker script.
  49. =============================================================================*/

  50. void __attribute__((interrupt, no_auto_psv)) _DMA0Interrupt(void)
  51. {
  52. if(DmaBuffer == 0)
  53. {
  54. ProcessADCSamples(&BufferA[1][1]);
  55. ProcessADCSamples(&BufferA[2][1]);
  56. ProcessADCSamples(&BufferA[3][1]);
  57. ProcessADCSamples(&BufferA[4][1]);
  58. ProcessADCSamples(&BufferA[5][1]);
  59. ProcessADCSamples(&BufferA[6][1]);
  60. ProcessADCSamples(&BufferA[7][1]);
  61. ProcessADCSamples(&BufferA[8][1]);
  62. }
  63. DmaBuffer ^= 1;
  64. IFS0bits.DMA0IF = 0; // Clear the DMA0 Interrupt Flag
  65. }

  66. void ProcessADCSamples(int * AdcBuffer)
  67. {
  68. adResults[adChannelCounter]=*AdcBuffer;
  69. adChannelCounter++;
  70. adChannelCounter&=0x7; //Allows 0-7

  71. AD1CHS0=adChannelMap[adChannelCounter]; //set the channel

  72. if (adChannelCounter==0) //rolled over, so we have 8 samples
  73. {
  74. shouldWriteResults = 1; //set flag.
  75. }
  76. }

    </code>
    Capture.PNG
 
IMHO, the problem is most likely the UART transmission rather than ADC. It looks like some of the characters get lost. This could be if, for example, you write to UART too fast, without waiting for the buffer. Once you fix that, you can work on ADC.
 
Thank much for your reply. I have tried increasing the baud rate but still no luck !! Can you please suggest anything else that could be wrong or missed?
 
Hi there,

Please find below the code of UART.

<code>
/*=======================================================================
UART Set UP
========================================================================= */

void initUART()
{
txFIFOtail = txFIFOhead = 0;
U1MODE=0;
U1MODEbits.BRGH = 1; // new baud rate of 468000
U1BRG=3;
U1MODE = 0x8800; //EN, no flow control, no BRGH
U1STA = 0x0400; //only TXEN
}

/*=======================================================================
Process UART FIFOs
========================================================================= */

void processUART()
{
char dummy=0;
U1STA&=0xFFFD; //lear the OERR bit
if (_U1RXIF)
{
dummy = U1RXREG;
_U1RXIF = 0;
//echo back //uartWriteByte(dummy);
if (dummy!=0x0d) //% 0xd 0xa is the ending of the line
{
if (uartCMDpos<16)
{
uartCMD[uartCMDpos++]=dummy;
} else
processUARTcmd();
} else
{
processUARTcmd();
}
}

if (!U1STAbits.UTXBF)
{
if (txFIFOtail != txFIFOhead)
{
U1TXREG = txFIFO[txFIFOtail];
txFIFOtail = (txFIFOtail + 1) & FIFO_MASK;
}
}
}

/*=======================================================================
Called when 0xa is received (\n) from the serial port.uartCMD array is
the line \r (not \n). uartCMDpos is the length of the line with \r
========================================================================= */

unsigned int portValues[5];

void processUARTcmd()
{
int i, dummy, wasError;
// unsigned int newOutput;
if (uartCMDpos==5)
{
wasError=0;
for (i=0; i<5; i++)
{
dummy = hexToNibble(uartCMD);
if (dummy!=-1) portValues=dummy; else { wasError=i+1; break; }
}
if (wasError)
{
uartWriteString("!ERROR - expected 5 HEX values\r\n");
}
else
{
LATB&=0x0FFF; LATB|=(portValues[4]<<12);
}
} else uartWriteString("!ERROR - must be 5 letters followed by \\r\\n\r\n");

uartCMDpos=0;
uartCMD[0]='\0';
}
</code>
 
Looks fine. May be you don't call your processUART() function often enough. On every invocation, you only send one symbol, so if you write more symbols than the number of processUART() calls, the buffer will overflow. If that's the case it'll be ok in the beginning (until the buffer fills in), but then it'll turn into something similar to what you see on the screen.
 
Thanks much for your reply. I'm calling processUART forever . Its in while(1) loop in the main code. Is there anything else which I can try or how to manage the size of UART buffer? Could you please provide some insight into this please?
 
"Forever" may not be enough. You main loop runs at some frequency (F1), and your ADC produces data at some frequency (F2). If F1 < F2, then your buffer will overflow. If you observe the pattern I described (good at the very beginning, then screwed) this is definitely the case. If that's the problem you can change your processUART() function so that it could send more than one byte.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top