[SOLVED] ADC problems - STM32F407 discovery
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-05-07 10:19 AM
I am using 2 ADCs with DMA in simultaneous mode and sending data over usb. Here is the code:
#include ''main.h''
const uint16_t BUFFER_SIZE = 400;
volatile uint16_t ADCConvertedValues [BUFFER_SIZE];
volatile uint16_t *head, *buffer_start, *buffer_end;
static void initialize_pointers(void);
static void buffer_step(void);
static void Hardware_Config(void);
static void ADC_Config(ADC_TypeDef*, uint8_t);
static void DMA_Config(void);
int main(void) {
initialize_pointers();
Hardware_Config();
ADC_SoftwareStartConv(ADC1);
while (1) {
usb_vcp_putc(*(head));
buffer_step();
usb_vcp_putc(*(head));
buffer_step();
}
}
static void Hardware_Config(void)
{
ADC_CommonInitTypeDef ADC_CommonInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable ADC1, ADC2, DMA and GPIO clocks */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
/* Enable DMA */
DMA_Config();
/* Configure ADC1_ch1 and ADC2_ch2 pins as analog input */
GPIO_InitStructure.GPIO_Pin = GPIO_PIN_1 | GPIO_Pin_2; // PA1, PA2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
/* ADC1 and ADC2 Init*/
ADC_Config(ADC1, ADC_Channel_1);
ADC_Config(ADC2, ADC_Channel_2);
/* Enable DMA request after last transfer (Multi-ADC mode) */
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
/* Enable ADC1 and ADC2*/
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
}
static void DMA_Config(){
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA2_Stream0);
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC->CDR; //0x40012308
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = sizeof(ADCConvertedValues)/sizeof(ADCConvertedValues[0]);
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream0, ENABLE);
}
static void ADC_Config(ADC_TypeDef* ADCx, uint8_t ADC_Channel){
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADCx, &ADC_InitStructure);
ADC_RegularChannelConfig(ADCx, ADC_Channel, 1, ADC_SampleTime_28Cycles); //84
}
static void initialize_pointers(){
buffer_start = ADCConvertedValues;
buffer_end = ADCConvertedValues + BUFFER_SIZE - 1;
head = ADCConvertedValues;
}
static void buffer_step() {
if (head == buffer_end) {
head = buffer_start;
} else {
head++;
}
}
1kHz sine is fed into channel 1 of ADC1. When I use
BUFFER_SIZE = 400I can get something that looks like a sine (sorry, I couldn't get that 'image manager' thing to work):
But when I increase buffer size to 1024 or 2048 the results look a lot worse:
Is there something wrong with my DMA configuration?
#adc #dma #discovery #board
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-05-07 10:49 AM
Is there something wrong with my DMA configuration?
Well it doesn't stop waiting for you to output to USB, and you have no flow control. The ADC+DMA fill the buffer at one rate, you output the buffer at some other rate, and they're not at all related.Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-05-07 11:03 AM
Thanks, Clive. I enabled the interrupt when DMA transfer is complete:
static
void
NVIC_Config() {
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
}
void
DMA2_Stream0_IRQHandler(
void
) {
if
(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)) {
buffer_increment_head_pointer();
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
}
}
This is the main loop after I added flow control:
uint8_t usb_cmd = 0;
while
(1) {
if
(usb_vcp_getc(&usb_cmd) == 0x50) {
/* host sent 'ready' command */
if
(buffer_overrun == 1) {
/* buffer is full - notify host */
usb_vcp_putc(0x56);
}
else
{
usb_vcp_putc(*(tail));
buffer_step();
usb_vcp_putc(*(tail));
buffer_step();
}
}
}
Basically I have *head and *tail pointers now that allow me to check for buffer overrun. Unfortunately, the problem persists even after I added flow control. The strange thing is that with small buffer size (400) I get better results than with a large buffer.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-05-07 1:04 PM
You might want to consider HT and TC, the buffer overwrites. Get some metrics about how fast each is iterating. ie use some GPIO and a scope to watch the HT and TC signals, and how fast the data is going across the USB.
Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-05-07 1:04 PM
I think I found the problem - I was using a blocking function
usb_vcp_getc()
in the main loop. Enabling an interrupt and processing data received from usb inside the interrupt seems to have solved the issue.
