cancel
Showing results for 
Search instead for 
Did you mean: 

Let's Decode some ADC+DMA output

troyerta
Associate II
Posted on January 08, 2016 at 19:21

 

 

The original post was too long to process during our migration. Please click on the attachment to read the original post.
8 REPLIES 8
Posted on January 08, 2016 at 19:56

Could you use the same sample time for both tests?

What's the pin tied too?

What values do you see if you tie the pin to either rail?

Toggling halves frequency

The second half of the buffer starts at [100] not [99]

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
troyerta
Associate II
Posted on January 08, 2016 at 20:48

Could you use the same sample time for both tests?

The sanity test is just a polling routine. But you give me the idea to try adding the timer trigger to it. It's the verification of the sampling time without the dma handler that makes doing so difficult.

I'll try doing it with the EOC interrupt, and try toggling a pin from there. Maybe the rate will still be 200 Hz? I think it will be. DMA would sure be nice to have though.

What's the pin tied too?

A small pot between Vcc and GND. But I've tried running the pin to the rails, because I know what the output should be if I do that. Triple checked for jumper connections on nucleo board, but connections are good as verified in the sanity check routine.

What values do you see if you tie the pin to either rail?

Same garbage of 30, 32, 32, 32, 30... etc.

Toggling halves frequency

Yep. I want to see GPIO rising edge on first half being filled, and falling edge for second half. But when I put hardware breakpoints in these two places, KEIL debugger watchpoint shows stuff all over the entire array getting updated between breakpoints. I think I'm just missing lots of interrupt calls between clicks of my mouse.

The second half of the buffer starts at [100] not [99]

Right, you caught my psuedo code mistake. Luckily, this function does not yet exist, though I have filled in a placeholder for now.

Posted on January 08, 2016 at 21:56

Ment ADC_SampleTime_15Cycles vs ADC_SampleTime_144Cycles

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
troyerta
Associate II
Posted on January 08, 2016 at 22:12

Having trouble saving my text here. Site is really slow today.

Anyways, I switched the sample time to 144 cycles which resulted in readings of 30... but now the readings are rock solid 30. No variability in the readings, no 29s, no 31s. Makes sense I guess. Larger integration time for greater precision.

Keil peripheral viewer shows ADC1->DR = 30 whenever I check it. So I think that confirms DMA operations as OK. Maybe I've zapped my ADC1 with static discharge.

I might try doing a configuration with ADC2 to see what happens. Might take some time look up the stream numbers and pin designations again. 

What are the odds of hardware error here? Large. I'm checking over my wiring again. I'm triple checking my channel and pin assignments. Any quirks to the 446s that you know about?

Posted on January 08, 2016 at 22:56

Not sure I have any 446 Nucleo's

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
troyerta
Associate II
Posted on January 11, 2016 at 19:55

I tried all the other channels on ADC1. All channels read 30. Except for CH16,17,18 which always read 12. Enabling the temp sensor on ch18 give believable values.

So I said screw it, and moved over to ADC2. Changed to the right DMA2 stream2, and read from CH10 to read PC0, and alas, I now have a constant stream of 49s.

Something is still up. 

Clocks are being turned on for GPIOC ports, peripherals, I've set the pins to analog in mode, with no pu/pd resistors... still goofy values. Anything more to try? Or is this just a bad guinea pig model?

raptorhal2
Lead
Posted on January 12, 2016 at 15:45

Channel 13 is PC3, not PC0.

Cheers, Hal

troyerta
Associate II
Posted on January 12, 2016 at 18:52

Alright, I've narrowed it down to a couple settings. Check this out.

/* Includes ------------------------------------------------------------------*/
#include ''main.h''
#include ''stdint.h''
#include ''stdlib.h''
#include ''stdio.h''
#include ''string.h''
#include ''ccd.h''
#include ''adc.h''
#include ''usart.h''
#include ''utils.h''
uint32_t i;
uint16_t j;
uint16_t sample = 0;
uint32_t done = 0;
volatile

uint16_t ADCConvertedValues[NUM_SAMPLES] = {0};
volatile

uint16_t

signal

[NUM_SAMPLES] = {0};
int

main(

void

)
{
done = 0;
LED_Setup();
GPIO_Setup();
RCC_Configuration();
USART3_Configuration();
GPIO(0);
LED(1);
/* Define ADC init structures */
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Enable timer (timer runs at 90 MHz)*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 449999;
TIM_TimeBaseStructure.TIM_Prescaler = 1;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_SelectOutputTrigger(TIM2,TIM_TRGOSource_Update);
//TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
NVIC_Init(&NVIC_InitStructure);
/* Enable clock on DMA1 & GPIOC */
/* Enable DMA2, thats where ADC is hooked on -> see Tab 20 (RM00090) */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_DMA2, ENABLE);
/* Initialise GPIOs C0 (ADC123_IN10), C1 (ADC123_IN11), C2 (ADC123_IN12)*/
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Initialise DMA */
DMA_StructInit(&DMA_InitStructure);
/* config of DMAC */
DMA_InitStructure.DMA_Channel = DMA_Channel_0;

/* See Tab 20 */

DMA_InitStructure.DMA_BufferSize = 200;

/* 200 * memsize */

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

/* direction */

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;

/* no FIFO */

DMA_InitStructure.DMA_FIFOThreshold = 0;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

/* circular buffer */

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

/* high priority */

/* config of memory */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues[0];

/* target addr */

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

/* 16 bit */

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);

/* See Table 20 for mapping */

DMA_Cmd(DMA2_Stream0, ENABLE);
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
DMA_Cmd(DMA2_Stream0, ENABLE);
/* IMPORTANT: populate default values before use */
ADC_StructInit(&ADC_InitStructure);
ADC_CommonStructInit(&ADC_CommonInitStructure);
/* reset configuration if needed, could be used for previous init */
ADC_Cmd(ADC1, DISABLE);
ADC_DeInit();
/* init ADC clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* init ADC */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* ADC1 Init: this is mostly done with ADC1->CR */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 2;

/* 2 channels in total */

ADC_Init(ADC1, &ADC_InitStructure);
/* Enable Vref & Temperature channel */
ADC_TempSensorVrefintCmd(ENABLE);
/* Configure channels */
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_18, 2, ADC_SampleTime_480Cycles);
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 **************************************************************/
ADC_Cmd(ADC1, ENABLE);
/* in main */
TIM_Cmd(TIM2, ENABLE);
while

(1)
{
//printf(''%d, %d, %d, %d, %d

'', ADCConvertedValues[0], ADCConvertedValues[1], ADCConvertedValues[2], ADCConvertedValues[3], ADCConvertedValues[4]);
for

(i = 0; i < 100000000; i++)
{
}
for

(i = 1; i < 200; i++)
{
printf

(

''block[%d] = %d, 

''

, i, ADCConvertedValues[i+1]);
i++;
}
for

(i = 0; i < 20000000; i++)
{
}
while

(1);
}
}
void

DMA2_Stream0_IRQHandler(

void

)

// Called at 2 Hz for 200 Hz sample rate, LED Toggles at 2 Hz

{
//uint16_t i = 0;
/* Test on DMA Stream Half Transfer interrupt */
if

(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0))
{
/* Clear DMA Stream Half Transfer interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
/* Turn LED3 off: Half Transfer */
GPIO(1);
done = 1;
// Add code here to process first half of buffer (ping)
//DMA_Cmd(DMA2_Stream0, DISABLE);
LED(0);
}
/* Test on DMA Stream Transfer Complete interrupt */
if

(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
/* Turn LED3 on: End of Transfer */
GPIO(0);
//DMA_Cmd(DMA2_Stream0, DISABLE);
LED(1);
// Add code here to process second half of buffer (pong)
// CountFallingEdges(&ADCConvertedValues[99],NUM_SAMPLES/2);
}
}

This works. I get legit ADC values by using this. Great. But I only want to sample 1 channel. By changing ADC_NbrOfConversion from 2 to 1 (Or from anything non-''one'' to one), and by removing the second call to ADC_RegularChannelConfig to enable only one channel, I get the 30s back. By adding in a second channel and second numbers of conversions to 2 or more, all the reading come in with legit values. Why would this happen?