При переносе обработки прерывания 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);
}
}