DMA и STM32L152RB

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Аватара пользователя
DimanVIP
Мучитель микросхем
Сообщения: 474
Зарегистрирован: Вт июн 01, 2010 22:12:07
Откуда: Тольятти
Контактная информация:

DMA и STM32L152RB

Сообщение DimanVIP »

Доброго всем времени суток!
Дано: плата STM32L-Discovery
Чип: STM32L152RB
IDE: Keil uVision 4.21.0
Задача: Пересылать значения из памяти в 4-й таймер, не затрагивая ядро.

Код: Выделить всё

#include <stm32l1xx.h>
#include <stm32l1xx_gpio.h>
#include <stm32l1xx_rcc.h>
#include <stm32l1xx_tim.h>
#include <stm32l1xx_dma.h>

const uint32_t dma_buffer[6] = { 64, 128, 255, 128, 64, 128 };

void mcu_dma_channel1_init(void)
{
  DMA_InitTypeDef DMA_Config;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  DMA_DeInit(DMA1_Channel1);
  DMA_Config.DMA_PeripheralBaseAddr = (uint32_t) & TIM4->CCR1;
  DMA_Config.DMA_MemoryBaseAddr = (uint32_t) & dma_buffer;
  DMA_Config.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_Config.DMA_BufferSize = 0x6;
  DMA_Config.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_Config.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_Config.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_Config.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_Config.DMA_Mode = DMA_Mode_Circular;
  DMA_Config.DMA_Priority = DMA_Priority_High;
  DMA_Config.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_Config);
  DMA_Cmd(DMA1_Channel1, ENABLE);
}

void mcu_tim4_init(void)
{        
  TIM_TimeBaseInitTypeDef TIM_BaseConfig;   
  TIM_OCInitTypeDef TIM_OCConfig;         
  GPIO_InitTypeDef GPIO_Config;
  RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOBEN, ENABLE);
  GPIO_Config.GPIO_Pin = GPIO_Pin_7;
  GPIO_Config.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Config.GPIO_OType = GPIO_OType_PP;
  GPIO_Config.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  GPIO_Config.GPIO_Speed = GPIO_Speed_40MHz;
  GPIO_Init(GPIOB, &GPIO_Config);
  GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_TIM4);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
 
  TIM_BaseConfig.TIM_Prescaler = (uint16_t) (SystemCoreClock / 4800000) - 1;   
  TIM_BaseConfig.TIM_Period = 0xff;
  TIM_BaseConfig.TIM_ClockDivision = TIM_CKD_DIV4;
  TIM_BaseConfig.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4, &TIM_BaseConfig);

  /* Channel1 Configuration in PWM mode */
  TIM_OCConfig.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCConfig.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCConfig.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCConfig.TIM_Pulse = 0x01;

  TIM_OC1Init(TIM4, &TIM_OCConfig);
  TIM_SelectOCxM(TIM4,TIM_Channel_1,TIM_OCMode_PWM1 );
  TIM_DMACmd (TIM4,TIM_DMA_CC1,ENABLE);
 
  TIM_Cmd(TIM4, ENABLE);
}

int main(void)
{
  mcu_dma_channel1_init();
  mcu_tim4_init();
  while (1)
    {
    }
}


Проблема: Не удается запустить DMA для 4-го таймера.
Симптомы: В отладчике регистр CCR1 меняет свои значения, но очень странно. Проскакивают значения из массива, но и проскакивают нули, которых там нет.
В железе не работает, диодик совсем не горит. Осцик показывает что там ничего нет.
[img]http://nekuru.com/images/DimanVIP/t2.png[/img]
Аватара пользователя
DimanVIP
Мучитель микросхем
Сообщения: 474
Зарегистрирован: Вт июн 01, 2010 22:12:07
Откуда: Тольятти
Контактная информация:

Re: DMA и STM32L152RB

Сообщение DimanVIP »

Имеется небольшой прогресс. Текущий код:

Код: Выделить всё

#include <stm32l1xx.h>
#include <stm32l1xx_gpio.h>
#include <stm32l1xx_rcc.h>
#include <stm32l1xx_tim.h>
#include <stm32l1xx_dma.h>

const uint32_t dma_buffer[6] = { 20, 30, 40, 50, 60, 70 };

void mcu_dma_channel1_init(void)
{
  DMA_InitTypeDef DMA_Config;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  DMA_DeInit(DMA1_Channel1);
  DMA_Config.DMA_PeripheralBaseAddr = (uint32_t)&TIM4->CCR1;
  DMA_Config.DMA_MemoryBaseAddr = (uint32_t)&dma_buffer;
  DMA_Config.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_Config.DMA_BufferSize = 6;
  DMA_Config.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_Config.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_Config.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
  DMA_Config.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
  DMA_Config.DMA_Mode = DMA_Mode_Circular;
  DMA_Config.DMA_Priority = DMA_Priority_High;
  DMA_Config.DMA_M2M = DMA_M2M_Enable;
  DMA_Init(DMA1_Channel1, &DMA_Config);
  DMA_Cmd(DMA1_Channel1, ENABLE);
}

void mcu_tim4_init(void)
{        
  TIM_TimeBaseInitTypeDef TIM_BaseConfig;   
  TIM_OCInitTypeDef TIM_OCConfig;            
  GPIO_InitTypeDef GPIO_Config;
 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOBEN, ENABLE);

  GPIO_Config.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_Config.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Config.GPIO_OType = GPIO_OType_PP;
  GPIO_Config.GPIO_Speed = GPIO_Speed_40MHz;
  GPIO_Init(GPIOB, &GPIO_Config);
  GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_TIM4);
  GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_TIM4);

  TIM_BaseConfig.TIM_Prescaler = (uint16_t) (SystemCoreClock / 4800000) - 1;   
  TIM_BaseConfig.TIM_Period = 149;
  TIM_BaseConfig.TIM_ClockDivision = 0;
  TIM_BaseConfig.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4, &TIM_BaseConfig);

  /* Channel1 Configuration in PWM mode */
  TIM_OCConfig.TIM_OCMode = TIM_OCMode_PWM1; 
  TIM_OCConfig.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCConfig.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCConfig.TIM_Pulse = 2;   
  TIM_OC1Init(TIM4, &TIM_OCConfig);
 
  /* Channel2 Configuration in PWM mode */
  TIM_OCConfig.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCConfig.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCConfig.TIM_Pulse = 29;
  TIM_OCConfig.TIM_OCPolarity = TIM_OCPolarity_Low;
  TIM_OC2Init(TIM4, &TIM_OCConfig);

  /* Enable TIM2 DMA interface */
  TIM_DMACmd(TIM4, TIM_DMA_CC1, ENABLE);
 
  TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
  TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
  TIM_ARRPreloadConfig(TIM4, ENABLE);
 
  TIM_Cmd(TIM4, ENABLE);   
}

int main(void)
{
  mcu_tim4_init();
  mcu_dma_channel1_init();
  while (1)
    {
    }
}

Симптомы: Когда гоняю в Кейловском отладчике, данные в таймер загоняются (даже светик от этого яркость меняет), но загоняются практически в случайном порядке (все данные из массива)
Когда запускаю в "свободный полет" и сажусь на ножку осциком, то вижу ШИМ с постоянной скважностью, т.е. регистр таймера не меняется.

У кого есть какие соображения?
[img]http://nekuru.com/images/DimanVIP/t2.png[/img]
Аватара пользователя
DimanVIP
Мучитель микросхем
Сообщения: 474
Зарегистрирован: Вт июн 01, 2010 22:12:07
Откуда: Тольятти
Контактная информация:

Re: DMA и STM32L152RB

Сообщение DimanVIP »

В общем рабочий код выглядит так:

Код: Выделить всё

#include <stm32l1xx.h>
#include <stm32l1xx_gpio.h>
#include <stm32l1xx_rcc.h>
#include <stm32l1xx_tim.h>
#include <stm32l1xx_dma.h>

const uint8_t dma_buffer[6] = { 20, 30, 40, 50, 60, 70 };

void mcu_dma_channel1_init(void)
{
  DMA_InitTypeDef DMA_Config;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  DMA_DeInit(DMA1_Channel1);         
  DMA_Config.DMA_PeripheralBaseAddr =   (uint32_t)&TIM4->CCR1;
  DMA_Config.DMA_MemoryBaseAddr = (uint32_t)&dma_buffer;
  DMA_Config.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_Config.DMA_BufferSize = 6;
  DMA_Config.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_Config.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_Config.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_Config.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_Config.DMA_Mode = DMA_Mode_Circular;
  DMA_Config.DMA_Priority = DMA_Priority_Low;
  DMA_Config.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_Config);
  DMA_Cmd(DMA1_Channel1, ENABLE);
}

void mcu_tim4_init(void)
{        
  TIM_TimeBaseInitTypeDef TIM_BaseConfig;    
  TIM_OCInitTypeDef TIM_OCConfig;          
  GPIO_InitTypeDef GPIO_Config;
 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOBEN, ENABLE);
 
  GPIO_Config.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_Config.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Config.GPIO_OType = GPIO_OType_PP;
  GPIO_Config.GPIO_Speed = GPIO_Speed_40MHz;
  GPIO_Init(GPIOB, &GPIO_Config);
  GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_TIM4);
  GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_TIM4);

  TIM_BaseConfig.TIM_Prescaler = 10 - 1;   
  TIM_BaseConfig.TIM_Period = 0xff;
  TIM_BaseConfig.TIM_ClockDivision = 0;
  TIM_BaseConfig.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4, &TIM_BaseConfig);

  /* Channel1 Configuration in PWM mode */
  TIM_OCConfig.TIM_OCMode = TIM_OCMode_PWM1; 
  TIM_OCConfig.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCConfig.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCConfig.TIM_Pulse = 1;
  TIM_OC1Init(TIM4, &TIM_OCConfig);

  /* Enable TIM2 DMA interface */
  TIM_DMACmd(TIM4, TIM_DMA_CC1, ENABLE);
  TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
  TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
  TIM_ARRPreloadConfig(TIM4, ENABLE);
  TIM_Cmd(TIM4, ENABLE);
}

int main(void)
{
  mcu_tim4_init();
  mcu_dma_channel1_init();
  while (1)
    {
    }
}

На выходе имеем:
Изображение
[img]http://nekuru.com/images/DimanVIP/t2.png[/img]
Аватара пользователя
van_de_luxe
Встал на лапы
Сообщения: 103
Зарегистрирован: Вс окт 31, 2010 16:46:10
Откуда: Оттуда

Re: DMA и STM32L152RB

Сообщение van_de_luxe »

Код: Выделить всё

DMA_Config.DMA_MemoryBaseAddr = (uint32_t)&dma_buffer;

меня эта строчка смущает
сейчас тоже занимаюсь DMA, только из памяти в UART
так вот, в DMA_MemoryBaseAddr как я понимаю должен передаваться адрес памяти, с которого начнется передача.
Но имя массива dma_buffer - это же и есть адрес его [0] элемента. &dma_buffer - получается адрес адреса? или компилятор это правильно распознает?
в примерах от ST написано

Код: Выделить всё

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer1;


И еще вопрос: где указывается число передаваемых символов (байт, полуслов, слов), как DMA определяет что нужно закончить брать данные из памяти? подозреваю что это DMA_BufferSize, но не уверен
Аватара пользователя
adrenocrome
Потрогал лапой паяльник
Сообщения: 365
Зарегистрирован: Вт окт 21, 2008 15:03:06
Откуда: moscow
Контактная информация:

Re: DMA и STM32L152RB

Сообщение adrenocrome »

van_de_luxe писал(а):
И еще вопрос: где указывается число передаваемых символов (байт, полуслов, слов), как DMA определяет что нужно закончить брать данные из памяти? подозреваю что это DMA_BufferSize, но не уверен

А это действительно так
День прошёл, а ты всё жив
Аватара пользователя
DimanVIP
Мучитель микросхем
Сообщения: 474
Зарегистрирован: Вт июн 01, 2010 22:12:07
Откуда: Тольятти
Контактная информация:

Re: DMA и STM32L152RB

Сообщение DimanVIP »

van_de_luxe писал(а):

Код: Выделить всё

DMA_Config.DMA_MemoryBaseAddr = (uint32_t)&dma_buffer;

меня эта строчка смущает
сейчас тоже занимаюсь DMA, только из памяти в UART
так вот, в DMA_MemoryBaseAddr как я понимаю должен передаваться адрес памяти, с которого начнется передача.
Но имя массива dma_buffer - это же и есть адрес его [0] элемента. &dma_buffer - получается адрес адреса? или компилятор это правильно распознает?
в примерах от ST написано

Код: Выделить всё

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer1;


И еще вопрос: где указывается число передаваемых символов (байт, полуслов, слов), как DMA определяет что нужно закончить брать данные из памяти? подозреваю что это DMA_BufferSize, но не уверен


& можно убрать, результат не изменится. Просто для чтения кода оставил.

На второй вопрос уже ответили.
[img]http://nekuru.com/images/DimanVIP/t2.png[/img]
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»