Перейти к содержанию
bbh_blocked_dnftl

Dx Portal DMA + таймер. ШИМ из массива.


Рекомендуемые сообщения

Вынес то что не получается в упрощенной форме в отдельный проект. Среда разработки CooCox 1.7.8, микроконтроллер STM32F103C8T6.

 

 

 

Нужно раз в ~100 мсек формировать на ножке МК, например,такую последовательность:

 

 

 

 

 

 

 

Стартовую длительность формирует таймер, в первом же своем прерывании по совпадению активирует DMA и дальше уже DMA по запросу таймера загружает значение CCR из массива. Что то похожее на управление светодиодами WS2812B. То что я сочинил выдает на пин:

 

 

 

 

 

 

Но только один раз при первом вызове. При последующих вызовах данные из массива выдаются без первоначальной длительности в 150 мкс.

 

 

 

Не могу найти ошибку.

 

 

 

 

 

 

 

#include

#include

#include

#include

#include

#include

 

GPIO_InitTypeDef PIN;

TIM_TimeBaseInitTypeDef TIM_Config;

TIM_OCInitTypeDef TIM_OCConfig;

DMA_InitTypeDef DMA_Setting;

 

uint8_t Test_Buf[] = {15,30,30,30,15};

 

void delay_ms(uint32_t ms) {

volatile uint32_t nCount;

RCC_ClocksTypeDef RCC_Clocks;

RCC_GetClocksFreq (&RCC_Clocks);

nCount = (RCC_Clocks.HCLK_Frequency/10000)*ms;

for (; nCount != 0; nCount--);

}

 

void Init_GPIO(void) {

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

 

PIN.GPIO_Pin = GPIO_Pin_11; // PA11 -> TIM1 Channel4

PIN.GPIO_Mode = GPIO_Mode_AF_PP;

PIN.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &PIN);

}

 

void Init_TIM_Transmit(void) {

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

 

TIM_TimeBaseStructInit(&TIM_Config); // настройки по дефолту

TIM_Config.TIM_Prescaler = 72-1; // Запускаем таймер на тактовой частоте 1 MHz (72000000/(72-1))

TIM_Config.TIM_Period = 150-1; // Период - 150 мкс

TIM_Config.TIM_ClockDivision = 0; // частоту дополнительно не делим

TIM_Config.TIM_CounterMode = TIM_CounterMode_Up; // считаем вверх

TIM_TimeBaseInit(TIM1, &TIM_Config); // Инициализируем TIM1

 

TIM_OCStructInit(&TIM_OCConfig); // настройки по дефолту

TIM_OCConfig.TIM_OCMode = TIM_OCMode_PWM1; // Конфигурируем как ШИМ (выравнивание по границе)

TIM_OCConfig.TIM_OutputState = TIM_OutputState_Enable; // Включаем выход

TIM_OCConfig.TIM_Pulse = 0; // CCR до старта пока нулевой

TIM_OCConfig.TIM_OCPolarity = TIM_OCPolarity_High; // Полярность

TIM_OCConfig.TIM_OCIdleState = TIM_OCIdleState_Reset; // состояние выхода по совпадению CCR (сброс)

 

TIM_OC4Init(TIM1, &TIM_OCConfig); // Инициализируем 4-й выход таймера, это PA11

TIM_ARRPreloadConfig(TIM1,ENABLE); // Предзагрузка периода (ARR)

TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable); // Предзагрузка длины импульса CCR 4-го канала

// (даем досчитать до конца и только потом значение меняется на новое)

TIM_DMACmd(TIM1,TIM_DMA_CC4,DISABLE); // выключаем пока запрос к DMA от таймера TIM1 по достижении CCR)

 

TIM_CtrlPWMOutputs(TIM1, ENABLE); // включаем выходы (это только для TIM1)

TIM_CCxCmd(TIM1,TIM_Channel_4,TIM_CCx_Enable); // разрешаем таймеру управлять выводом PA11

TIM_ITConfig(TIM1, TIM_IT_CC4, DISABLE); // запрещаем пока таймеру генерировать прерывание по совпадению

NVIC_EnableIRQ(TIM1_CC_IRQn); // разрешаем прерывания

TIM_Cmd(TIM1, DISABLE); // Выключаем таймер (пока ждем)

}

 

void TIM1_CC_IRQHandler(void) // прошло 130 мкс

{

if (TIM_GetITStatus(TIM1, TIM_IT_CC4) != RESET) { // по совпадению

TIM_ClearITPendingBit(TIM1,TIM_IT_CC4); // сбрасываем флаг прерывания TIM1 по совпадению

}

 

NVIC_EnableIRQ(TIM1_CC_IRQn); // выключаем прерывания от таймера

TIM_ITConfig(TIM1, TIM_IT_CC4, DISABLE); //

 

TIM1->ARR = 40-1; // устанавливаем период 40 мкс

TIM1->CCR4 = Test_Buf[0]; // ширину из массива для следующего импульса

 

DMA1_Channel4->CNDTR = 4; // длина данных для DMA на 1 меньше т.к. уже установили выше 1 элемент

 

TIM_DMACmd(TIM1,TIM_DMA_CC4,ENABLE); // разрешаем таймеру делать запрос к DMA по совпадению CCR

DMA_Cmd(DMA1_Channel4, ENABLE); // включаем DMA

}

 

void Init_DMA(void)

{

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // включаем тактирование DMA1

 

DMA_Setting.DMA_PeripheralBaseAddr = (uint32_t) &TIM1->CCR4; // куда копировать

DMA_Setting.DMA_MemoryBaseAddr = (uint32_t) &Test_Buf[1]; // что копировать

DMA_Setting.DMA_DIR = DMA_DIR_PeripheralDST; // копируем в периферию (Peripheral Destination, точка назначения - периферия)

DMA_Setting.DMA_BufferSize = 0; // количество передаваемых данных

DMA_Setting.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // адрес периферии постоянный

DMA_Setting.DMA_MemoryInc = DMA_MemoryInc_Enable; // адрес в памяти увеличиваем

DMA_Setting.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // периферия 16 бит

DMA_Setting.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // массив 8 бит

DMA_Setting.DMA_Mode = DMA_Mode_Normal; // режим обычный

DMA_Setting.DMA_Priority = DMA_Priority_Medium; // приоритет средний

DMA_Setting.DMA_M2M = DMA_M2M_Disable; // MemoryToMemory откл.

 

DMA_Init(DMA1_Channel4, &DMA_Setting); // TIM1_CH4 относится к 4-му каналу DMA1

DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE); // настраиваем прерывание по окончанию передачи

NVIC_EnableIRQ(DMA1_Channel4_IRQn); // включаем прерывания от 4-го канала DMA1

DMA_Cmd(DMA1_Channel4, DISABLE); // пока выключаем 4-ый канал DMA1

}

 

void DMA1_Channel4_IRQHandler(void) // закончили передавать

{

if (DMA_GetITStatus(DMA1_IT_TC4) != RESET) { // по совпадению

DMA_ClearITPendingBit(DMA1_IT_TC4); // сбрасываем флаг прерывания DMA1 Channel4 transfer complete

}

if (TIM_GetITStatus(TIM1, TIM_IT_CC4) != RESET) { // по совпадению

TIM_ClearITPendingBit(TIM1,TIM_IT_CC4); // сбрасываем флаг прерывания TIM1 на всякий случай

}

 

TIM1->ARR = 150-1; // вновь настраиваем на период 150 мкс

TIM1->CCR4 = 0; // и ждем следующею передачу

TIM1->CNT = 0; //

 

TIM_DMACmd(TIM1,TIM_DMA_CC4,DISABLE); // всё выключаем

DMA_Cmd(DMA1_Channel4, DISABLE); //

TIM_Cmd(TIM1, DISABLE); //

TIM_ITConfig(TIM1, TIM_IT_CC4, DISABLE); //

 

TIM_CCxCmd(TIM1,TIM_Channel_4,TIM_CCx_Disable);

}

 

int main(void)

{

Init_GPIO();

Init_TIM_Transmit();

Init_DMA();

 

delay_ms(1000);

 

while(1)

{

TIM1->CCR4 = 130-1; // до включения линия удерживается в 0 (CCR=0)

TIM_ITConfig(TIM1, TIM_IT_CC4, ENABLE);

TIM_CCxCmd(TIM1,TIM_Channel_4,TIM_CCx_Enable);

TIM_Cmd(TIM1, ENABLE);

 

delay_ms(100);

}

}

 

 

 

 

 

TEST_TIM_DMA.zip

 

Читать дальше

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
×
×
  • Создать...