STM32–ЦАП + ПДП

19 Апреля 2011 К комментариям

В прошлый раз приведя пару примеров работы с библиотекой от STMicroelectronics, я не думал что для работы с мк установленным в STM32VLDiscovery используется другая библиотека. А так как большинство имеет на руках именно STM32VLDiscovery, то сегодня попытаюсь исправить свою ошибку и рассмотрю работу с ЦАП и ПДП (DMA).

В примерах предлагаемых производителем, я не нашел работу с ЦАП и ПДП, но примеры были в ранее рассмотренной библиотеке, поэтому я их немного поправил под мк установленный на плате STM32VLDiscovery.

И так начнем с самого простого и самого любимого с генерации ЦАП-ом обычной синусоиды.

Один из возможных вариантов решения поставленной задачи: по таймеру запускать преобразования ЦАП, по запросам ЦАП запускать ПДП для записи нового значения из памяти в ЦАП.

Вся настройка сводится к уже привычному списку:

  • разрешить тактирование
  • настроить режим работы
  • разрешить работу
  • Разрешаем тактирование ЦАП, ПДП, таймера:
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM7, ENABLE);
    Настраиваем режим работы таймера 7:
    	// конфигурируем таймер 7
    	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    	TIM_TimeBaseStructure.TIM_Period = 0x80;
    	TIM_TimeBaseStructure.TIM_Prescaler = 0;
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
    
    	TIM_SelectOutputTrigger(TIM7, TIM_TRGOSource_Update);
    Таймер 7 выбран не случайно, он может быть выбран в качестве источника запуска для ЦАП: image Настраиваем и разрешаем работу ПДП канал 3:
    // конфигурируем ПДП1 канал 3
    DMA_DeInit(DMA1_Channel3);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & DAC->DHR12R1;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32) &sinus_12bit;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = ARRAY_LENGHT(sinus_12bit);
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel3, &DMA_InitStructure);
    
    DMA_Cmd(DMA1_Channel3, ENABLE);
    Канал 3 контроллера ПДП, так же выбран не случайно, именно к нему “привязан” запрос от ЦАП: image Настраиваем и разрешаем работу ЦАП:
    // конфигурируем ЦАП
    DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
    DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
    DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
    DAC_Init(DAC_Channel_1, &DAC_InitStructure);
    
    DAC_Cmd(DAC_Channel_1, ENABLE);
    
    DAC_DMACmd(DAC_Channel_1, ENABLE);
    В последнюю очередь разрешаем работу таймера 7, так как именно он является инициатором: // разрешаем работу таймера 7 TIM_Cmd(TIM7, ENABLE); Код целиком:
    int main(void)
    {
    	DAC_InitTypeDef DAC_InitStructure;
    	DMA_InitTypeDef DMA_InitStructure;
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    
    	// инициализируем систему тактирования
    	RCC_Configuration();
    
    	// настраиваем линии ввода-вывода
    	PIN_CONFIGURATION(DAC1_OUTPUT);
    	PIN_CONFIGURATION(PIN_TEST);
    
    	PIN_ON(PIN_TEST);
    
    	// конфигурируем таймер 7
    	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    	TIM_TimeBaseStructure.TIM_Period = 0x300;
    	TIM_TimeBaseStructure.TIM_Prescaler = 0;
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
    
    	TIM_SelectOutputTrigger(TIM7, TIM_TRGOSource_Update);
    
    	// конфигурируем ПДП1 канал 3
    	DMA_DeInit(DMA1_Channel3);
    	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & DAC->DHR12R1;
    	DMA_InitStructure.DMA_MemoryBaseAddr = (u32) &sinus_12bit;
    	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    	DMA_InitStructure.DMA_BufferSize = ARRAY_LENGHT(sinus_12bit);
    	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    	DMA_Init(DMA1_Channel3, &DMA_InitStructure);
    
    	DMA_Cmd(DMA1_Channel3, ENABLE);
    
    	// конфигурируем ЦАП
    	DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = 0;
    	DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
    	DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
    	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
    	DAC_Init(DAC_Channel_1, &DAC_InitStructure);
    
    	DAC_Cmd(DAC_Channel_1, ENABLE);
    
    	DAC_DMACmd(DAC_Channel_1, ENABLE);
    
    	// разрешаем работу таймера 7
    	TIM_Cmd(TIM7, ENABLE);
    
    	while (1)
    	{
    	}
    
    	return 0;
    }
    Всё можно зашивать и любоваться синусоидой на выводе PA4. Отдельно касательно тактирования мк, после сброса тактирование всегда идет от встроенного генератора, но не плохо бы выжать “максимум” для этого необходимо разрешить работу внешнего высокочастотного генератора, настроить систему ФАПЧ, для умножения на 3 (на плате установлен кварц на 8 МГц, максимальная частота мк 24 МГц):
    //------------------------------------------------------------------------------
    void RCC_Configuration(void)
    {
    	ErrorStatus HSEStartUpStatus;
    
    	// активируем работу HSE
    	RCC_HSEConfig(RCC_HSE_ON);
    
    	// ожидаем готовности
    	HSEStartUpStatus = RCC_WaitForHSEStartUp();
    
    	if (HSEStartUpStatus == SUCCESS)
    	{
    		// разрешаем предварительую выборку
    		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    
    		// задержка равна нулю
    		FLASH_SetLatency(FLASH_Latency_0);
    
    		// HCLK = SYSCLK
    		RCC_HCLKConfig(RCC_SYSCLK_Div1);
    
    		// PCLK2 = HCLK
    		RCC_PCLK2Config(RCC_HCLK_Div1);
    
    		// PCLK1 = HCLK
    		RCC_PCLK1Config(RCC_HCLK_Div1);
    
    		// PLLCLK = 8MHz * 3 = 24 MHz
    		RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_3);
    
    		// разрешаем ФАПЧ
    		RCC_PLLCmd(ENABLE);
    
    		// ожидаем готовности ФАПЧ
    		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    		{
    		}
    
    		// выбираем в качестве системного тактового сигнала
    		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    
    		// ожидаем пока будет выбранна
    		while (RCC_GetSYSCLKSource() != 0x08)
    		{
    		}
    	}
    
    	// разрешаем тактирвание
    	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM7, ENABLE);
    }
    Проект одним файлом: 2011-04-19-stm32vldiscovery-dac-dma Размер после компиляции: Linking: target.elf ----------------------------------------------------------- text data bss dec hex filename 1880 0 200 2080 820 target/target.elf


comments powered by Disqus