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
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.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.
2015-05-07 01: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.
2015-05-07 01: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.