При переносе обработки прерывания DMA в main() программа перестает работать правильно

UPD. Забыл сразу написать что речь идет о контроллере 1986ВЕ4У.

Суть такая. Если вот так, вызывать функции переконфигурации DMA и пересылки всего буфера DMA прямо из обработчика прерывания, то все работает отлично.

static void adc_dma()
{
    RST_CLK_PCLKcmd((RST_CLK_PCLK_RST_CLK | RST_CLK_PCLK_DMA | RST_CLK_PCLK_ADC |
                    RST_CLK_PCLK_PORTA | RST_CLK_PCLK_PORTB), ENABLE);

    RST_CLK_PCLKcmd((RST_CLK_PCLK_SSP1), ENABLE);

    adc_init();

    DMA_ChannelInitTypeDef DMA_InitStr;
    DMA_ChannelInitTypeDef *DMA_InitStrPtr = &DMA_InitStr;

    DMA_CtrlDataInitTypeDef DMA_PriCtrlStr;
    DMA_CtrlDataInitTypeDef *DMA_PriCtrlStrPtr = &DMA_PriCtrlStr;

    DMA_CtrlDataInitTypeDef DMA_AltCtrlStr;
    DMA_CtrlDataInitTypeDef *DMA_AltCtrlStrPtr = &DMA_AltCtrlStr;

    dma_init(DMA_InitStrPtr, DMA_PriCtrlStrPtr, DMA_AltCtrlStrPtr,
             DMA_BUFFER_SIZE, ADCConvertedValue);

    ADC1_Cmd(ENABLE);
    NVIC_EnableIRQ(DMA_IRQn);

    while (1);
}

void DMA_IRQHandler(void)
{
    UART_send_string_(CYCLE_NUMBER_STRING, cycles);
    cycles++;
    UART_send_values(ADCConvertedValue);
    DMA_reconfigure();
}

Если же использовать переменную типа флаг, в прерывании выставлять ее в true и делать поллинг этой переменной в основной программе, то работает неправильно.

static volatile bool dma_cycle_ended;
static volatile int cycles = 1;


while (1) {
    UART_send_string_("DMA cycle state: %d\r\n", dma_cycle_ended);

    if (dma_cycle_ended) {
        UART_send_string_("Interrupt No %d\r\n\n", interrupts_count);

        NVIC_DisableIRQ(DMA_IRQn);
        NVIC_ClearPendingIRQ(DMA_IRQn);

        UART_send_string_(CYCLE_NUMBER_STRING, cycles);
        UART_send_values(ADCConvertedValue);
        DMA_reconfigure();

        cycles++;
        dma_cycle_ended = false;

        NVIC_EnableIRQ(DMA_IRQn);
    }
}

void DMA_IRQHandler(void)
{
        interrupts_count++;
        dma_cycle_ended = true;
        UART_send_string_("dma cycle state in INTERRUPT = %d\r\n", dma_cycle_ended);
}

При таком коде UART пересылает такое (хватает на 2 цикла, дальше не возвращается из прерывания в основной цикл).

dma cycle state in INTERRUPT = 1
DMA cycle state: 1
Interrupt No 1

Цикл DMA номер '1' окончен. Результаты измерений:

ADC value '1' = 2010
ADC value '2' = 2009
ADC value '3' = 2010
......
ADC value '254' = 2010
ADC value '255' = 2010
ADC value '256' = 2010

dma cycle state in INTERRUPT = 1
DMA cycle state: 1
Interrupt No 2

Цикл DMA номер '2' окончен. Результаты измерений:

ADC value '1' = 2010
ADC value '2' = 2010
ADC value '3' = 2010
......
ADC value '254' = 2010
ADC value '255' = 2010
ADC value '256' = 2011
dma cycle state in INTERRUPT = 1
dma cycle state in INTERRUPT = 1
dma cycle state in INTERRUPT = 1
....... и так до бесконечности

Причем так работает если дергать разрешения прерывания каждый раз. Если убрать строчки

  NVIC_DisableIRQ(DMA_IRQn);
  NVIC_ClearPendingIRQ(DMA_IRQn);
  NVIC_EnableIRQ(DMA_IRQn)

то затыкается даже до начала отправки значений первого цикла. Это без отправки строки из прерывания.

DMA cycle state: 1
Interrupt No 1

Цикл DMA номер '1' оконч

При отправке строки вывод такой, но тут просто сообщения перетирают друг друга, насколько я понял

dma cycle state in INTERRUPT = 1
DMAdma cycle state in INTERRUPT = 1
cycle sdma cycle state in INTERRUPT = 1
dma cycle state in INTERRUPT = 1
dma cycle state in INTERRUPT = 1
dma cycle state in INTERRUPT = 1
.....

Еще раз скажу что при варианте, который представлен все работает идеально, циклы DMA формируются и пересылаются правильно до бесконечности.

Очевидно что-то не так с логикой программы? И стоит ли так уж стараться убрать обработку из обработчика прерывания (извините за тавтологию)?

Функции, которые могут оказаться релевантными:

DMA

 extern DMA_CtrlDataTypeDef DMA_ControlTable[DMA_Channels_Number * (1+DMA_AlternateData)];
uint32_t DMA_ChannelCtrl;


void dma_init(DMA_ChannelInitTypeDef *DMA_InitStrPtr,
              DMA_CtrlDataInitTypeDef *DMA_PriCtrlStrPtr,
              DMA_CtrlDataInitTypeDef *DMA_AltCtrlStrPtr,
              int buffer_size, uint16_t ADCConvertedValue[buffer_size])
{
    DMA_DeInit();
    DMA_StructInit(DMA_InitStrPtr);

    DMA_PriCtrlStrPtr->DMA_SourceBaseAddr = (uint32_t)(&(MDR_ADC->ADC1_RESULT));
    DMA_PriCtrlStrPtr->DMA_DestBaseAddr = (uint32_t)ADCConvertedValue;
    DMA_PriCtrlStrPtr->DMA_SourceIncSize = DMA_SourceIncNo;
    DMA_PriCtrlStrPtr->DMA_DestIncSize = DMA_DestIncHalfword;
    DMA_PriCtrlStrPtr->DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_PriCtrlStrPtr->DMA_Mode = DMA_Mode_PingPong;
    DMA_PriCtrlStrPtr->DMA_CycleSize = buffer_size;
    DMA_PriCtrlStrPtr->DMA_NumContinuous = DMA_Transfers_1;
    DMA_PriCtrlStrPtr->DMA_SourceProtCtrl = DMA_SourcePrivileged;
    DMA_PriCtrlStrPtr->DMA_DestProtCtrl = DMA_DestPrivileged;

    DMA_AltCtrlStrPtr->DMA_SourceBaseAddr = (uint32_t)(&(MDR_ADC->ADC1_RESULT));
    DMA_AltCtrlStrPtr->DMA_DestBaseAddr   = (uint32_t)ADCConvertedValue;
    DMA_AltCtrlStrPtr->DMA_SourceIncSize = DMA_SourceIncNo;
    DMA_AltCtrlStrPtr->DMA_DestIncSize = DMA_DestIncHalfword;
    DMA_AltCtrlStrPtr->DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_AltCtrlStrPtr->DMA_Mode = DMA_Mode_PingPong;
    DMA_AltCtrlStrPtr->DMA_CycleSize = buffer_size;;
    DMA_AltCtrlStrPtr->DMA_NumContinuous = DMA_Transfers_1;
    DMA_AltCtrlStrPtr->DMA_SourceProtCtrl = DMA_SourcePrivileged;
    DMA_AltCtrlStrPtr->DMA_DestProtCtrl = DMA_DestPrivileged;

    DMA_InitStrPtr->DMA_PriCtrlData = DMA_PriCtrlStrPtr;
    DMA_InitStrPtr->DMA_AltCtrlData = DMA_AltCtrlStrPtr;
    DMA_InitStrPtr->DMA_Priority = DMA_Priority_Default;
    DMA_InitStrPtr->DMA_UseBurst = DMA_BurstClear;
    DMA_InitStrPtr->DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY;

    DMA_Init(DMA_Channel_ADC, DMA_InitStrPtr);

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

    DMA_Read_ChannelCtrl(DMA_Channel_ADC, &DMA_ChannelCtrl);
}

void DMA_reconfigure()
{
    DMA_Write_ChannelCtrl(DMA_Channel_ADC, DMA_ChannelCtrl);
    DMA_Cmd(DMA_Channel_ADC, ENABLE);
}

void DMA_Read_ChannelCtrl(uint32_t DMA_Channel, uint32_t *dmaControl)
{
    *dmaControl = DMA_ControlTable[DMA_Channel].DMA_Control;
}

void DMA_Write_ChannelCtrl(uint32_t DMA_Channel, uint32_t dmaControl)
{
    DMA_ControlTable[DMA_Channel].DMA_Control = dmaControl;
}

UART

void UART_send_values(uint16_t adc_values[])
{
    int value_number;
    for(value_number = 0; value_number < DMA_BUFFER_SIZE; value_number++) {
        char buffer[50];
        sprintf(buffer, "ADC value '%d' = %d\r\n", value_number + 1, adc_values[value_number]);
        UART_send_string(buffer);
    }
}


void UART_send_string_(const char *str, int value)
{
    uint16_t counter = 0;
    size_t string_length = strlen(str);
    char buffer[string_length];
    sprintf(buffer, str, value);

    while(buffer[counter]) {
        UART_SendData(MDR_UART1, (uint16_t) buffer[counter++]);
        delay_short(Del_250_ns);
    }
}

Ответы (0 шт):