Wiki

Clone wiki

Milandr / ADC DMA

По переполнению таймера создается запрос в ДМА который устанавливает бит ADC1_CFG_REG_GO в регистре ADC1_CFG, который стартует преобразование АЦП. После выполнения преобразования создается запрос на передачу результата преобразования из регистра ADC1_RESULT в массив ADCConvertedValue. По выполнении ADC_BUFFER/2 передач DMA вызывает прерывание в котором по очереди в зависимости от текущей рабочей конфигурации (Primary / Alternative) счетчик передач в DMA переинициализируется и заново устанавливается режим DMA DMA_Mode_PingPong.

#!c
    #define ADC_BUFFER  32
    uint16_t ADCConvertedValue[ADC_BUFFER];
    uint32_t ADC_Go = ADC1_CFG_REG_GO | 0x0C002201;

    /* DMA Configuration */
    /* Reset all settings */
    DMA_DeInit();

/* DMA ADC1 */
    DMA_StructInit(&DMA_InitStr);
    /* Set Primary Control Data */
    DMA_PriCtrlStr.DMA_SourceBaseAddr = (uint32_t)(&(MDR_ADC->ADC1_RESULT));
    DMA_PriCtrlStr.DMA_DestBaseAddr = (uint32_t)&ADCConvertedValue[0];
    DMA_PriCtrlStr.DMA_SourceIncSize = DMA_SourceIncNo;
    DMA_PriCtrlStr.DMA_DestIncSize = DMA_DestIncHalfword;
    DMA_PriCtrlStr.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_PriCtrlStr.DMA_Mode = DMA_Mode_PingPong;
    DMA_PriCtrlStr.DMA_CycleSize = ADC_BUFFER/2;
    DMA_PriCtrlStr.DMA_NumContinuous = DMA_Transfers_1;
    DMA_PriCtrlStr.DMA_SourceProtCtrl = DMA_SourcePrivileged;
    DMA_PriCtrlStr.DMA_DestProtCtrl = DMA_DestPrivileged;

    /* Set Alternate Control Data */
    DMA_AltCtrlStr.DMA_SourceBaseAddr = (uint32_t)(&(MDR_ADC->ADC1_RESULT));
    DMA_AltCtrlStr.DMA_DestBaseAddr   = (uint32_t)&ADCConvertedValue[ADC_BUFFER/2];
    DMA_AltCtrlStr.DMA_SourceIncSize = DMA_SourceIncNo;
    DMA_AltCtrlStr.DMA_DestIncSize = DMA_DestIncHalfword;
    DMA_AltCtrlStr.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_AltCtrlStr.DMA_Mode = DMA_Mode_PingPong;
    DMA_AltCtrlStr.DMA_CycleSize = ADC_BUFFER/2;
    DMA_AltCtrlStr.DMA_NumContinuous = DMA_Transfers_1;
    DMA_AltCtrlStr.DMA_SourceProtCtrl = DMA_SourcePrivileged;
    DMA_AltCtrlStr.DMA_DestProtCtrl = DMA_DestPrivileged;

    /* Set Channel Structure */
    DMA_InitStr.DMA_PriCtrlData = &DMA_PriCtrlStr;
    DMA_InitStr.DMA_AltCtrlData = &DMA_AltCtrlStr;
    DMA_InitStr.DMA_Priority = DMA_Priority_Default;
    DMA_InitStr.DMA_UseBurst = DMA_BurstClear;
    DMA_InitStr.DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY;

    /* Init DMA channel ADC1 */
    DMA_Init(DMA_Channel_ADC1, &DMA_InitStr);

    /* Enable dma_req or dma_sreq to generate DMA request */
    MDR_DMA->CHNL_REQ_MASK_CLR = (1<<DMA_Channel_ADC1);
    MDR_DMA->CHNL_USEBURST_CLR = (1<<DMA_Channel_ADC1);

    /* Enable DMA channel ADC1 */
    DMA_Cmd(DMA_Channel_ADC1, ENABLE);

/* DMA Timer1 */
    /* Set Primary Control Data */
    DMA_PriCtrlStr.DMA_SourceBaseAddr = (uint32_t)(&ADC_Go);
    DMA_PriCtrlStr.DMA_DestBaseAddr = (uint32_t)(&(MDR_ADC->ADC1_CFG));
    DMA_PriCtrlStr.DMA_SourceIncSize = DMA_SourceIncNo;
    DMA_PriCtrlStr.DMA_DestIncSize = DMA_DestIncNo;
    DMA_PriCtrlStr.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
    DMA_PriCtrlStr.DMA_Mode = DMA_Mode_PingPong;
    DMA_PriCtrlStr.DMA_CycleSize = ADC_BUFFER/2;
    DMA_PriCtrlStr.DMA_NumContinuous = DMA_Transfers_1;
    DMA_PriCtrlStr.DMA_SourceProtCtrl = DMA_SourcePrivileged;
    DMA_PriCtrlStr.DMA_DestProtCtrl = DMA_DestPrivileged;

    /* Set Alternate Control Data */
    DMA_AltCtrlStr.DMA_SourceBaseAddr = (uint32_t)(&ADC_Go);
    DMA_AltCtrlStr.DMA_DestBaseAddr   = (uint32_t)(&(MDR_ADC->ADC1_CFG));
    DMA_AltCtrlStr.DMA_SourceIncSize = DMA_SourceIncNo;
    DMA_AltCtrlStr.DMA_DestIncSize = DMA_DestIncNo;
    DMA_AltCtrlStr.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
    DMA_AltCtrlStr.DMA_Mode = DMA_Mode_PingPong;
    DMA_AltCtrlStr.DMA_CycleSize = ADC_BUFFER/2;
    DMA_AltCtrlStr.DMA_NumContinuous = DMA_Transfers_1;
    DMA_AltCtrlStr.DMA_SourceProtCtrl = DMA_SourcePrivileged;
    DMA_AltCtrlStr.DMA_DestProtCtrl = DMA_DestPrivileged;

    /* Set Channel Structure */
    DMA_InitStr.DMA_PriCtrlData = &DMA_PriCtrlStr;
    DMA_InitStr.DMA_AltCtrlData = &DMA_AltCtrlStr;
    DMA_InitStr.DMA_Priority = DMA_Priority_Default;
    DMA_InitStr.DMA_UseBurst = DMA_BurstClear;
    DMA_InitStr.DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY;

    /* Init DMA channel Timer1 */
    DMA_Init(DMA_Channel_TIM1, &DMA_InitStr);

    /* Enable dma_req or dma_sreq to generate DMA request */
    MDR_DMA->CHNL_REQ_MASK_CLR = (1<<DMA_Channel_TIM1);
    MDR_DMA->CHNL_USEBURST_CLR = (1<<DMA_Channel_TIM1);

    /* Enable DMA channel Timer1 */
    DMA_Cmd(DMA_Channel_TIM1, ENABLE);


    /* Enable DMA IRQ */
    NVIC_EnableIRQ(DMA_IRQn);
#!c

void Initialize_Timers (void)
{
    TIMER_CntInitTypeDef    TIMER_CntInitStructure;                         

    /* TIMER1 Configuration -------------------------------------------------  */
    RST_CLK_PCLKcmd(RST_CLK_PCLK_TIMER1, ENABLE);
    TIMER_DeInit(MDR_TIMER1);                                               // Deinitializes the TIMERx peripheral registers to their default reset values.
    TIMER_CntStructInit(&TIMER_CntInitStructure);                           // Fills each TIMER_CntInitStruct member with its default value.
    TIMER_CntInitStructure.TIMER_Prescaler = 0;
    TIMER_CntInitStructure.TIMER_Period = 148;                              // 56Mhz/12.5kbps/2 halfwave/3 chan/5 samples = 149,333
    TIMER_CntInit(MDR_TIMER1, &TIMER_CntInitStructure);                     // Initializes the TIMERx Counter peripheral according to the specified parameters in the TIMER_CntInitStruct.

    TIMER_BRGInit(MDR_TIMER1,TIMER_HCLKdiv1);                               /* Enable TIMER1 clock */
    TIMER_Cmd(MDR_TIMER1, ENABLE);                                          // Enables or disables the specified TIMER peripheral.

    TIMER_DMACmd(MDR_TIMER1, TIMER_STATUS_CNT_ARR, ENABLE);
}
#!c

void Initialize_ADC (void)
{
    /* ADC Configuration */
    RST_CLK_PCLKcmd(RST_CLK_PCLK_ADC,ENABLE);
    /* Reset all ADC settings */
    ADC_DeInit();
    ADC_StructInit(&sADC);

    sADC.ADC_SynchronousMode      = ADC_SyncMode_Independent;           
    sADC.ADC_StartDelay           = 0;
    sADC.ADC_IntVRefConversion    = ADC_VREF_CONVERSION_Disable;
    sADC.ADC_IntVRefTrimming      = 1;
    ADC_Init (&sADC);

    /* ADC1 Configuration */
    ADCx_StructInit (&sADCx);
    sADCx.ADC_ClockSource      = ADC_CLOCK_SOURCE_CPU;
    sADCx.ADC_SamplingMode     = ADC_SAMPLING_MODE_SINGLE_CONV;
    sADCx.ADC_ChannelSwitching = ADC_CH_SWITCHING_Enable;
    sADCx.ADC_Channels         = ADC_CH_ADC0_MSK | ADC_CH_ADC1_MSK | ADC_CH_ADC2_MSK;
    sADCx.ADC_LevelControl     = ADC_LEVEL_CONTROL_Disable;
    sADCx.ADC_LowLevel         = 0;
    sADCx.ADC_HighLevel        = 0;
    sADCx.ADC_VRefSource       = ADC_VREF_SOURCE_INTERNAL;
    sADCx.ADC_IntVRefSource    = ADC_INT_VREF_SOURCE_INEXACT;
    sADCx.ADC_Prescaler        = ADC_CLK_div_4;
    sADCx.ADC_DelayGo          = 6;
    ADC1_Init (&sADCx);

    /* Enable ADC1 EOCIF and AWOIFEN interupts */
    ADC1_ITConfig((ADCx_IT_END_OF_CONVERSION  | ADCx_IT_OUT_OF_RANGE), DISABLE);

    /* ADC1 enable */
    ADC1_Cmd (ENABLE);
}
#!c

void DMA_IRQHandler(void)
{
    if((MDR_DMA->CHNL_PRI_ALT_SET & (1<<DMA_Channel_ADC1)) == (0<<DMA_Channel_ADC1))
    {
        DMA_ControlTable[DMA_Channel_ADC1+32].DMA_Control |= ((ADC_BUFFER/2 - 1) << 4) | DMA_Mode_PingPong;
        DMA_ControlTable[DMA_Channel_TIM1+32].DMA_Control |= ((ADC_BUFFER/2 - 1) << 4) | DMA_Mode_PingPong;
        PORT_WriteBit(MDR_PORTA, PORT_Pin_0, Bit_SET);

    }
    else if((MDR_DMA->CHNL_PRI_ALT_SET & (1<<DMA_Channel_ADC1)) == (1<<DMA_Channel_ADC1))
    {
        DMA_ControlTable[DMA_Channel_ADC1].DMA_Control |= ((ADC_BUFFER/2 - 1) << 4) | DMA_Mode_PingPong;
        DMA_ControlTable[DMA_Channel_TIM1].DMA_Control |= ((ADC_BUFFER/2 - 1) << 4) | DMA_Mode_PingPong;
        Ready = 1;
        PORT_WriteBit(MDR_PORTA, PORT_Pin_0, Bit_RESET);
    }
}

Updated