2017-02-22 03:04 PM
Device: STM32F437
I am using ADC3 channels 5 (rank 1) and 8 (rank 2) in interleaved mode, the input for channel 5 is 0 volts and the input for channel 8 is near upper limit. Trapping after the first interrupt the 32 location array looks correct, counts near zero for the even locations, and high counts for the odd locations. However, on all subsequent occasions the pattern is reversed.
Is there some type of resetting action I need to take after a transfer is complete? I have included some code below so you can see how I have set up the ADC and DMA. I trimmed it down as much as I thought practical but apologize that it is still rather lengthy.
Thanks,
jh
OS_SEM adc_done;
static uint16_t adc3_result[ADC_NUM_READINGS*ADC_NUM_CHANNELS];static const uint8_t injected_map[4] = {
ADC_InjectedChannel_1, ADC_InjectedChannel_2, ADC_InjectedChannel_3, ADC_InjectedChannel_4};void AnalogTask(void *parg)
{ OS_ERR err; uint8_t spoke; uint16_t adcA, adcB, adcInj; static chan_data_t aux; // Also used for auxiliary dataAdcInit();
for(;;) {
AdcMux(0, READING_V, READING_V); //setup regular and inj chans OSTimeDly(OS_CFG_TICK_RATE_HZ/100, OS_OPT_TIME_PERIODIC, &err); if (err != OS_ERR_NONE) { APP_CATCH('ERROR: AnalogTask()::OSTimeDly() failed'); } adcInj=AdcRead(&adcA, &adcB); A[spoke] = adcA/16; B[spoke] = adcB/16; }}void AdcInit(void)
{ ADC_InitTypeDef init; NVIC_InitTypeDef nvic; OS_ERR err; uint8_t i; OSSemCreate(&adc_done, 'ADC DMA Complete', 0, &err); if (err != OS_ERR_NONE) { APP_CATCH('ERROR: AdcInit()::OSSemCreate() failed'); } RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); DMA_DeInit(DMA2_Stream0); ADC_DeInit(); ADC_StructInit(&init); init.ADC_ScanConvMode = ENABLE; init.ADC_ContinuousConvMode = ENABLE; init.ADC_NbrOfConversion = ADC_NUM_CHANNELS; ADC_Init(ADC3, &init); ADC_Cmd(ADC3, ENABLE); // DMA to be done later... // Base config for Injected channel conversion: ADC_InjectedSequencerLengthConfig(ADC3, 4); for (i=0; i<4; i++) { ADC_SetInjectedOffset(ADC3, injected_map[i], 0); } nvic.NVIC_IRQChannel = DMA2_Stream0_IRQn; nvic.NVIC_IRQChannelPreemptionPriority = 1; nvic.NVIC_IRQChannelSubPriority = 0; nvic.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvic); ADC_DMARequestAfterLastTransferCmd(ADC3, DISABLE); DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);}static const DMA_InitTypeDef dma2 =
{ DMA_Channel_2, ADC3_BASE+0x4C, // ADC3->DR (uint32_t)&adc3_result[0], //Mememory 0 base addre DMA_DIR_PeripheralToMemory, //Direction DMA_DIR_PeripheralToMemory,DMA_DIR_MemoryToPeripheral,DMA_DIR_MemoryToMemory ADC_NUM_READINGS*ADC_NUM_CHANNELS, //Buffer size DMA_PeripheralInc_Disable, // Increment or not DMA_MemoryInc_Enable, // Increment or not DMA_PeripheralDataSize_HalfWord, //_Byte, _HalfWord, _Word DMA_MemoryDataSize_HalfWord, //Same DMA_Mode_Normal, //_NOrmal or _Circular DMA_Priority_Medium, DMA_FIFOMode_Disable, DMA_FIFOThreshold_1QuarterFull, DMA_MemoryBurst_Single, DMA_PeripheralBurst_Single};void AdcMux(void){ uint8_t i; // Set MUX pins GPIO_WriteBit(GPIOD, GPIO_Pin_3, 1); GPIO_WriteBit(GPIOD, GPIO_Pin_4, 0); // Configure 'core' channels ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 1, ADC_SampleTime_480Cycles); ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 2, ADC_SampleTime_480Cycles); // Configure injected read for (i=1; i <= 4; i++) { ADC_InjectedChannelConfig(ADC3, ADC_Channel_14), i, ADC_SampleTime_480Cycles); } // Go ahead and read the injected channels ADC_SoftwareStartInjectedConv(ADC3);}uint16_t AdcRead(uint16_t *bankA, uint16_t *bankB)
{ OS_ERR err; CPU_TS ts; uint32_t i; uint16_t inj=0, a=0, b=0; uint16_t *result=&adc3_result[0];DMA_Init(DMA2_Stream0, (DMA_InitTypeDef*)&dma2);
DMA_Cmd(DMA2_Stream0, ENABLE); ADC_DMACmd(ADC3, ENABLE); ADC_SoftwareStartConv(ADC3); OSSemPend(&adc_done, 0, OS_OPT_PEND_BLOCKING, &ts, &err); if (err != OS_ERR_NONE) { APP_CATCH('ERROR: AdcRead()::OSSemPend() failed'); } ADC_DMACmd(ADC3, DISABLE); //16 for (i = 0; i < ADC_NUM_READINGS; i++) { a += *result++; b += *result++;if (i < 4) {
inj += ADC_GetInjectedConversionValue(ADC3, injected_map[i]); } } *bankA=a; *bankB=b; return inj;}void Adc3ISR(void)
{ OS_ERR err; CPU_SR_ALLOC(); CPU_INT_DIS(); OSIntNestingCtr++; CPU_INT_EN();if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) == SET)
//if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TC) == SET) { DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); OSSemPost(&adc_done, OS_OPT_POST_1, &err); if (err != OS_ERR_NONE) { APP_CATCH('ERROR: Adc3ISR()::OSSemPost() failed'); } }OSIntExit();
}2017-02-24 05:41 AM
I am wondering if the problem is related to the fact that my code disables and re-enables ADC_DMACmd(). This is necessary because the inputs need to be re-configured between sample sets. This is how the enable/disable is done:
DMA_Init(DMA2_Stream0, (DMA_InitTypeDef*)&dma2);
DMA_Cmd(DMA2_Stream0, ENABLE); ADC_DMACmd(ADC3, ENABLE); ADC_SoftwareStartConv(ADC3); OSSemPend(&adc_done, 0, OS_OPT_PEND_BLOCKING, &ts, &err); if (err != OS_ERR_NONE) { APP_CATCH('ERROR: AdcRead()::OSSemPend() failed'); } ADC_DMACmd(ADC3, DISABLE);The examples I have found so far run continuously w/o starting and stopping.
I would appreciate it if you could point me to a sample of interleaved reading that turns the process off and on as we are trying to do.
Thanks,
jh
2017-02-24 07:10 AM
Common initialization was missing so I added the following to AdcInit() to eliminate a cause but it made no difference.
cInit.ADC_Mode = ADC_DualMode_Interl;
cInit.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; cInit.ADC_DMAAccessMode = ADC_DMAAccessMode_1; cInit.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInit(&cInit);