Sl (07.07.2017 19:38, просмотров: 9096)
Добрый день. stm32f746IG + IAR 8.11 + ST-link. Помогите разобраться с проблемой DMA2. Не получается запустить ADC1 -> DMA2. Уже несколько дней бьюсь. Не раз читал reference manual (RM0385), AN4031 (Application note Using the STM32F2, STM32F4 and STM32F7 Series DMA controller), Errata.
Пытаюсь запустить самый простой вариант - преобразования 5-ми регулярных каналов. ADC1 -> DMA2_Stream_4_Channel0 -> U16Dma2DataADC1[].
Причем:
- Все это раньше успешно делал для Stm32f107
- в stm32f746IG уже успешно работает связка DMA2 -> USART1
- после инициализации ADC1 и DMA2 удается успешно перебросить данные АЦП ТОЛЬКО ОДИН раз!
Попытка еще раз запустить ADC1 -> DMA2 не “проходит”, пока не сброшу процессор.
Т.е. я вижу, что преобразования в ADC1 завершились ADC1->SR.EOC = 1, но DMA2_Stream4 не “запустилось” DMA2_Stream4->CR.EN=1
и DMA2_Stream4->NDTR = 5 (не уменьшилось до нуля).
Все прерывания запрещены.
Между первым запуском и последующим запуском ADC1 -> DMA2 пауза 100 mks.
Пытался размещать массив для ADC1 как в SRAM1, так и в SRAM2, так и в DTCM RAM. Результат одинаково неуспешный.
Команда U16Dma2DataADC1[0]++; работает. Т.е. массив в расположен в SRAM.
Перед повторным запуском флаги прерывания используемого потока сбрасываю с помощью DMA2->LIFCR и DMA2->HIFCR.
В подпрограмме повторного запуска есть лишние “телодвижения”. Но это уже от безысходности .
Конечно, тактирование ADC1 и DMA2 разрешено. Все входы ADC1,2,3 определены как аналоговые.
Очень большое подозрение, что где то устанавливается или флаг ошибки или еще какое то запрещение работы DMA2. Но, я этого не вижу.
ADCCLK = PCLK2/4 = 27000000
volatile uint16_t U16Dma2DataADC1[16]; // ADC1.
// ***********************************************************************
Подпрограмма инициализации ADC1 для работы с DMA.
void SInitContinueChannelDMA_ADC1(void)
{
// ADCPRE[1:0] = 1. ADCCLK = 108Mhz/4 = 27 Mhz.
ADC->CCR = 0x00010000;
// 12 bit. Enable Scan mode.
ADC1->CR1 =((ADC_12bit<<ADCx_CR1_RES) | (ADC_CR1_SCAN * 1));
#define ADCx_CR2_DMA_init ((ADC_CR2_ALIGN * 0) | \
(ADC_CR2_EOCS * 0) | \
(ADC_CR2_DMA * 1) | \
(ADC_CR2_CONT * 0) | \
(ADC_CR2_ADON * 1))
ADC1->CR2 = ADCx_CR2_DMA_init;
#define ADCx_SR_init 0x00000000
ADC1->SR = ADCx_SR_init;
ADC1->SMPR1 = 0x00000000;
ADC1->SMPR2 = 0x00000000;
ADC1->HTR = 0x00000FFF;
ADC1->LTR = 0x00000000;
// Будет запущено 5 каналов.
#define ADC1_SQR1_init ((5<<20) | 0x00000000)
#define ADC1_SQR2_init 0x00000000
#define ADC1_SQR3_init ((0 <<25) | (Uin3 <<20) | (Uin2 <<15) | (Uin1 <<10) | (Iin2 <<5) | (Iin1 << 0))
ADC1->SQR1 = ADC1_SQR1_init;
ADC1->SQR2 = ADC1_SQR2_init;
ADC1->SQR3 = ADC1_SQR3_init;
ADC1->JSQR = 0x00000000;
ADC1->DR; // Empty read.
ADC->CDR; // Empty read.
}
// ***********************************************************************
Подпрограмма инициализации DMA для работы с ADC1.
void SInitDMA2_f74x_75x(void)
{
// Сбрасываю все флаги прерываний всех потоков.
#define DMA_LIFCR_all_clear (uint32_t)(0x0F7D0F7D) // DMA all interrupt flags clear.
DMA2->LIFCR = DMA_LIFCR_all_clear;
#define DMA_HIFCR_all_clear (uint32_t)(0x0F7D0F7D) // DMA all interrupt flags clear.
DMA2->HIFCR = DMA_HIFCR_all_clear;
ADC1->CR2 |= ADC_CR2_DMA;
// Запрещаю работу DMA2_Stream4.
LSStream4Disable:
DMA2_Stream4->CR &= ~DMA_SxCR_EN;
if((DMA2_Stream4->CR & DMA_SxCR_EN) != 0) goto LSStream4Disable;
// Адрес источника.
DMA2_Stream4->PAR = (uint32_t)&ADC1->DR; // 0x4001.2000 + 0x004C.
// Адрес первого элемента массива.
DMA2_Stream4->M0AR = (uint32_t)&U16Dma2DataADC1[0x00];
// Количество пересылаемых 16битных значений.
DMA2_Stream4->NDTR = 5;
// 0 - Chanel. - (0<<DMA_SxCR_Chanel)
// memory single transfer. - (DMASingleTransfer<<DMA_SxCR_MBurstConfig)
// peripheral single transfer. - (DMASingleTransfer<<DMA_SxCR_PBurstConfig)
// запрещаем работу с двойным буффером - (DMA_SxCR_DBM * 0)
// Высокий приоритет - DMAHighPrioritet.
// Периферийный адрес НЕ увеличивается исходя из записанного в PSIZE - PINCOS=0.
// Память передает 16-bits(DMA_Data16 << DMA_SxCR_MemSize), а периферия принимает 16-bits(DMA_Data16 << DMA_SxCR_PerphSize).
// Адрес памяти увиличивается (DMA_SxCR_MINC*1), а адрес периферии не увеличивается (DMA_SxCR_PINC*0).
// Circular mode disabled. (DMA_SxCR_CIRC*0).
// Peripheral-to-Memory. (DMA_Peripheral_memory << DMA_SxCR__DIR).
// Peripheral flow controller no use. (DMA_SxCR_PFCTRL*0).
// DMA Transfer complete interrupt enable. (DMA_SxCR_TCIE*1).
#define DMA2_Stream4_CR_DMA_ADC1_init ((0<<DMA_SxCR_Chanel) | \
(DMASingleTransfer<<DMA_SxCR_MBurstConfig) | \
(DMASingleTransfer<<DMA_SxCR_PBurstConfig) | \
(DMA_SxCR_DBM * 0) | \
(DMAHighPrioritet << DMA_SxCR_Prioritet) | \
(DMA_SxCR_PINCOS * 0) | \
(DMA_Data16 << DMA_SxCR_MemSize) | (DMA_Data16 << DMA_SxCR_PerphSize) | \
(DMA_SxCR_MINC*1) | (DMA_SxCR_PINC*0) | \
(DMA_SxCR_CIRC*0) | \
(DMA_Peripheral_memory << DMA_SxCR__DIR) | \
(DMA_SxCR_PFCTRL*0) | \
(DMA_SxCR_TCIE*1))
DMA2_Stream4->CR = DMA2_Stream4_CR_DMA_ADC1_init;
// Direct mode enabled.
DMA2_Stream4->FCR &= ~ ((uint32_t)(DMA_SxFCR_DMDIS));
}
// ***********************************************************************
Подпрограмма первого старта ADC1 -> DMA2_Stream_4_Channel0 -> U16Dma2DataADC1[].
void SStartDMA_ADC1(void)
{
DMA2_Stream4->CR |= DMA_SxCR_EN;
ADC1->SR &= ~ADC_SR_STRT; // 0x00000010. Clear Regular channel Start flag.
ADC1->CR2 |= ADC_CR2_SWSTART; //0x40000000. Start Conversion of regular channels.
}
// ***********************************************************************
Подпрограмма второго и последующих стартов ADC1 -> DMA2_Stream_4_Channel0 -> U16Dma2DataADC1[].
void SReStartDMA_ADC1(void)
{
LSReStream4Disable:
DMA2_Stream4->CR &= ~DMA_SxCR_EN;
if((DMA2_Stream4->CR & DMA_SxCR_EN) != 0) goto LSReStream4Disable;
register uint32_t RegPRIMASKGFAB124_tmp;
RegPRIMASKGFAB124_tmp = __get_PRIMASK();
__disable_irq();
// сбрасываю перед повторным запуском все флаги прерывания для используемого потока.
DMA2->HIFCR = DMA_HIFCR_AllStream4_clear; // 0x0000003D.
// Адрес источника.
DMA2_Stream4->PAR = (uint32_t)&ADC1->DR; // 0x4001.2000 + 0x004C.
// Адрес первого элемента массива.
DMA2_Stream4->M0AR = (uint32_t)&U16Dma2DataADC1[0x00];
// Количество пересылаемых 16битных значений.
DMA2_Stream4->NDTR = 5;
DMA2_Stream4->CR |= DMA_SxCR_EN;
ADC1->DR; // Empty read.
ADC->CDR; // Empty read.
ADC1->SR &= ~ADC_SR_STRT; // 0x00000010. Clear Regular channel Start flag.
ADC1->CR2 |= ADC_CR2_SWSTART; //0x40000000. Start Conversion of regular channels.
__set_PRIMASK(RegPRIMASKGFAB124_tmp);
}
// ***********************************************************************