Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Запуск одного таймера от другого
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Quantum1
Добрый день!

Пытаюсь на камне stm32f103 сделать следующее.

Первый таймер считает, на процовой частоте к примеру, досчитав до определенного значения запускает еще два таймера в режиме одного импульса.
Основная цель что бы эти 2 таймера запускались точно в заданный момент и одновременно. А и еще, это должно происходить автоматически, т.е. не програмно - настроил таймеры запустил первый и забыл.

Пытаюсь с триггеры таймеров крутить, но черт возьми - ничего не выходит.

Если подскажите как это сделать буду крайне благодарен, желательно на spl*)

Спасибо!
Haamu
Цитата(Quantum1 @ Aug 7 2014, 10:47) *
Основная цель что бы эти 2 таймера запускались точно в заданный момент и одновременно. А и еще, это должно происходить автоматически, т.е. не програмно - настроил таймеры запустил первый и забыл.


Почему бы не запустить эти два таймера в прерывании от первого? Будет конечно разница в несколько системных тиков. Или синхронность абсолютная нужна? Поясните задачу целиком.
adnega
Цитата(Quantum1 @ Aug 7 2014, 10:47) *
Если подскажите как это сделать буду крайне благодарен, желательно на spl*)

Нужно использовать каскадное включение таймеров. Первый таймер будет мастером для двух других таймеров, которые будут слейвами. Есть так называемый "Gated Mode" или как Вы уже правильно заметили "Trigger Mode".
Распишите поробнее TRGO мастер-таймера и TRGI слейвов.
Типа TIM1->PWM1->TRGO
TRGI_TIM1->ITR0->TIM2
TRGI_TIM1->ITR0->TIM3

Второй вариант TIM->CR2: MMS
Цитата
Enable - the Counter Enable signal CNT_EN is used as trigger output (TRGO). It is
useful to start several timers at the same time or to control a window in which a slave timer is
enable. The Counter Enable signal is generated by a logic OR between CEN control bit and
the trigger input when configured in gated mode. When the Counter Enable signal is
controlled by the trigger input, there is a delay on TRGO, except if the master/slave mode is
selected (see the MSM bit description in TIMx_SMCR register).
Quantum1
Цитата(adnega @ Aug 8 2014, 11:28) *
Нужно использовать каскадное включение таймеров. Первый таймер будет мастером для двух других таймеров, которые будут слейвами. Есть так называемый "Gated Mode" или как Вы уже правильно заметили "Trigger Mode".
Распишите поробнее TRGO мастер-таймера и TRGI слейвов.
Типа TIM1->PWM1->TRGO
TRGI_TIM1->ITR0->TIM2
TRGI_TIM1->ITR0->TIM3

Второй вариант TIM->CR2: MMS


А может сумеете подсказать какой-нить рабочий пример?



Цитата(Haamu @ Aug 8 2014, 10:39) *
Почему бы не запустить эти два таймера в прерывании от первого? Будет конечно разница в несколько системных тиков. Или синхронность абсолютная нужна? Поясните задачу целиком.


с прерываниями не вариант - нужно, что бы запустил и забыл.
adnega
Цитата(Quantum1 @ Aug 8 2014, 15:24) *
А может сумеете подсказать какой-нить рабочий пример?

Собственно, я его и привел.
Хоите конкретики, вначале сами дайте конкретику.
Какие таймеры доступны, какие интервалы нужны, вплоть до конкретных пинов МК и т.п?
Quantum1
Цитата(adnega @ Aug 8 2014, 15:46) *
Собственно, я его и привел.
Хоите конкретики, вначале сами дайте конкретику.
Какие таймеры доступны, какие интервалы нужны, вплоть до конкретных пинов МК и т.п?


А зачем интервалы и тем более пины?

Нужен просто пример где один таймер, к примеру при CNT=CCR1, запускает другие два таймера, к примеру в режиме одиночного импульса. Какая разница будет там секунда или микросекунда в периоде.
Сама идея что нужно делать понятна...
Я пробовал играться с SPL, но результат нулевой... вообще некоторые функции связанные с триггерами мне мало понятны, у сожалению*)
Да, я пытался расписывать все эти мастеры, слейвы, экстернал триггеры и клоки, что бы вывести сигнал с одного таймера на его выходной триггер, а потом подключить к нему два других итд... но только еще больше запутался.

Если поможите буду очень благодарен.

я к сожалению плохо зная stm32 (знал бы хорошо вопросов бы не было конечно*))
Знаю по опыту, если тупик, можно и неделю биться и все бестолку.
А можно один ма-а-аленький примерчик глянуть и за 5 минут все решить*)
adnega
Цитата(Quantum1 @ Aug 12 2014, 15:53) *
А можно один ма-а-аленький примерчик глянуть и за 5 минут все решить*)

Не согласен, но можете поробовать. Это самый маленький пример каскадного использования сразу 4 таймеров, DMA и SPI.
К сожалению, на вопросы отвечать не готов. И стандартной библиотекой я не пользуюсь.
Пять минут пошли... )))
CODE
#ifdef TABLO_MODE_DYNAMIC2
//-----------------------------------------------------------------------------
// void __inline init_DMA1_CH6(int phase)
//-----------------------------------------------------------------------------
void __inline init_DMA1_CH6(int phase)
{
volatile int i;
// con_str("*");
// con_start();

TIM3->CR1 = 0;
TIM1->CR1 = 0;
TIM1->DIER = (0 << TIM_DIER_CC1DE);

DMA1_Channel6->CCR =
(DMA_PL_HIGH << DMA_CCR_PL) // приоритет высокий
| (DMA_SIZE_BYTE << DMA_CCR_MSIZE) // размер памяти 8-бит
| (DMA_SIZE_BYTE << DMA_CCR_PSIZE) // размер периферии 8-бит
| (1 << DMA_CCR_DIR)
| (1 << DMA_CCR_MINC) // автоинкремент памяти
| (0 << DMA_CCR_CIRC) // циклический буфер
| (0 << DMA_CCR_HTIE) // прерывание полузаполнения
| (0 << DMA_CCR_TCIE) // прерывание полного заполнения
| (0 << DMA_CCR_EN); // канал выключен

DMA1_Channel6->CPAR = SPI1_DR; // адрес периферийного регистра

DMA1_Channel6->CMAR = (vu32)&dynamic_video_trans[0]; // адрес буфера в памяти

DMA1_Channel6->CNDTR = DYNAMIC_VIDEO_SIZE; // размер буфера памяти

T1_STB_bit = 0;

DMA1->IFCR = (1 << DMA_ISR_TCIF6);
TIM1->DIER = (1 << TIM_DIER_CC1DE);
TIM1->CNT = 0;
TIM1->EGR = (1 << TIM_EGR_UG);
TIM1->SR = 0;

DMA1_Channel6->CCR =
(DMA_PL_HIGH << DMA_CCR_PL) // приоритет высокий
| (DMA_SIZE_BYTE << DMA_CCR_MSIZE) // размер памяти 8-бит
| (DMA_SIZE_BYTE << DMA_CCR_PSIZE) // размер периферии 8-бит
| (1 << DMA_CCR_DIR)
| (1 << DMA_CCR_MINC) // автоинкремент памяти
| (0 << DMA_CCR_CIRC) // циклический буфер
| (0 << DMA_CCR_HTIE) // прерывание полузаполнения
| (0 << DMA_CCR_TCIE) // прерывание полного заполнения
| (1 << DMA_CCR_EN); // канал включен

TIM15->CNT = 0;
TIM15->EGR = (1 << TIM_EGR_UG);
TIM15->CR1 =
(1 << TIM_CR1_CEN)
| (1 << TIM_CR1_OPM)
| (1 << TIM_CR1_ARPE);

TIM3->CNT = 0;
TIM3->EGR = (1 << TIM_EGR_UG);
TIM3->SR = 0;

TIM1->CR1 = (1 << TIM_CR1_CEN);
TIM3->CR1 = (1 << TIM_CR1_CEN);

TIM17->CNT = 0;
}

//-----------------------------------------------------------------------------
// void __inline init_TIMER1(void)
//-----------------------------------------------------------------------------
void __inline init_TIMER1(void)
{
TIM1->CR1 = 0;

if(rcc_state == RCC_STATE_PLL)
{
TIM1->PSC = (FPLL / FHSI) - 1;
}
else
{
TIM1->PSC = 0;
}

TIM1->ARR = (300) - 1;
TIM1->EGR = (1 << TIM_EGR_UG);

TIM1->CCR1 = 1; // импульс "DMA транзакция"
TIM1->CCER = (1 << TIM_CCER_CC1E); // импульс "DMA транзакция"
TIM1->CCMR1 = (OC_MODE_PWM1 << TIM_CCMR1_OC1M); // импульс "DMA транзакция"
TIM1->CCMR2 = 0;
TIM1->CR2 = 0;
TIM1->SMCR =
(0 << TIM_SMCR_TS) // ITR0 = TIM15
| (5 << TIM_SMCR_SMS); // GATED_MODE

TIM1->BDTR = (1 << TIM_BDTR_MOE);
TIM1->DIER = (1 << TIM_DIER_CC1DE);
}

//-----------------------------------------------------------------------------
// void __inline init_TIMER15(void)
//-----------------------------------------------------------------------------
void __inline init_TIMER15(void)
{
TIM15->CR1 = 0;
TIM15->EGR = (1 << TIM_EGR_UG);
TIM15->PSC = 0;
TIM15->ARR = 0xFFFF;
TIM15->SMCR =
(7 << TIM_SMCR_SMS) // EXTERNAL_CLOCK
| (1 << TIM_SMCR_TS); // ITR1 = TIM3

TIM15->CCR1 = (DYNAMIC_VIDEO_SIZE / DYNAMIC_VIDEO_N) + 0;

TIM15->CCER = (1 << TIM_CCER_CC1E);
TIM15->CCMR1 = (OC_MODE_PWM1 << TIM_CCMR1_OC1M);
TIM15->CCMR2 = 0;
TIM15->CR2 = (4 << TIM_CR2_MMS); // TRGO = OC1REF
TIM15->DIER = 0;
TIM15->BDTR = (1 << TIM_BDTR_MOE);
TIM15->CR1 =
(0 << TIM_CR1_CEN)
| (1 << TIM_CR1_OPM)
| (1 << TIM_CR1_ARPE);
}

//-----------------------------------------------------------------------------
// void __inline init_TIMER3(void)
//-----------------------------------------------------------------------------
void __inline init_TIMER3(void)
{
TIM3->CR1 = 0;

if(rcc_state == RCC_STATE_PLL)
{
TIM3->PSC = (FPLL / FHSI) - 1; // запись периода
TIM3->ARR = (300 * 32) - 1; // запись базы
TIM3->CCR3 = TIM3->ARR - 100; // импульс "сдвиг"
TIM3->CCR4 = TIM3->ARR - 200; // импульс "защелка"
}
else
{
TIM3->PSC = 0; // запись периода
TIM3->ARR = (300 * 32) - 1; // запись базы
TIM3->CCR3 = 1; //TIM2->ARR - 2; // импульс "сдвиг"
TIM3->CCR4 = TIM3->ARR - 1; // импульс "защелка"
}
TIM3->EGR = (1 << TIM_EGR_UG);

TIM3->CCR1 = 8; // импульс "DMA транзакция"
TIM3->CCR2 = TIM3->ARR - 200; // импульс "счет"
TIM3->CCER =
(1 << TIM_CCER_CC1E) // импульс "DMA транзакция"
| (1 << TIM_CCER_CC2E) // импульс "счет"
| (1 << TIM_CCER_CC3E) // импульс "защелка"
| (1 << TIM_CCER_CC4E); // импульс "сдвиг"

TIM3->CCMR1 =
(OC_MODE_PWM2 << TIM_CCMR1_OC1M) // импульс "DMA транзакция"
| (OC_MODE_PWM2 << TIM_CCMR1_OC2M); // импульс "счет"

TIM3->CCMR2 =
(OC_MODE_PWM2 << TIM_CCMR2_OC3M) // импульс "защелка"
| (OC_MODE_PWM2 << TIM_CCMR2_OC4M); // импульс "сдвиг"

TIM3->CR2 = (5 << TIM_CR2_MMS); // TRGO = OC2REF
TIM3->SMCR =
(2 << TIM_SMCR_TS) // ITR2 = TIM15
| (5 << TIM_SMCR_SMS); // GATED_MODE

TIM3->DIER = 0;

}

//-----------------------------------------------------------------------------
// void __inline init_TIMER16(void)
//-----------------------------------------------------------------------------
void __inline init_TIMER16(void)
{
if(rcc_state == RCC_STATE_PLL)
TIM16->PSC = (10 * FPLL / FHSI) - 1;
else
TIM16->PSC = (10) - 1;
TIM16->ARR = (800000 / FDYNAMIC_REFRESH) - 1;
TIM16->CR1 = 0;
TIM16->CCMR1 = 0;
TIM16->CCER = 0;
TIM16->SMCR = 0;
TIM16->DIER = (1 << TIM_DIER_UIE);
TIM16->BDTR = (1 << TIM_BDTR_MOE);
TIM16->CR1 = (1 << TIM_CR1_CEN);
}

//-----------------------------------------------------------------------------
// void __inline init_SPI1(void)
//-----------------------------------------------------------------------------
void __inline init_SPI1(void)
{
SPI1->CR1 =
(0 << SPI_CR1_SPE)
| (0 << SPI_CR1_DFF)
| (1 << SPI_CR1_SSM)
| (1 << SPI_CR1_SSI)
| (1 << SPI_CR1_MSTR)
| (3 << SPI_CR1_BR);

SPI1->CR2 =
(0 << SPI_CR2_RXNEIE)
| (0 << SPI_CR2_TXDMAEN)
| (1 << SPI_CR2_SSOE);

SPI1->CR1 =
(1 << SPI_CR1_SPE)
| (0 << SPI_CR1_DFF)
| (1 << SPI_CR1_SSM)
| (1 << SPI_CR1_SSI)
| (1 << SPI_CR1_MSTR)
| (3 << SPI_CR1_BR);
}
//-----------------------------------------------------------------------------
// void TIM1_TRG_COM_TIM17_IRQHandler(void)
//-----------------------------------------------------------------------------
void TIM1_TRG_COM_TIM17_IRQHandler(void) __attribute__((interrupt("IRQ")));
void TIM1_TRG_COM_TIM17_IRQHandler(void)
{
static int phase = 0;
static int dyn_cnt = 0;
int i;

if(TIM17->SR & (1 << TIM_SR_UIF))
{
TIM17->SR &= ~(1 << TIM_SR_UIF);

// DYNAMIC

for(i = 0; i < 40; i++) T1_STORE_bit = 0;

T1_STORE_bit = 1;
T1_STORE_bit = 0;

if(dyn_cnt > 7)
{
T1_STB_bit = 1;
T1_CLK_bit = 1;
T1_CLK_bit = 0;
T1_STB_bit = 0;
dyn_cnt = 0;
}
else
{
T1_CLK_bit = 1;
T1_CLK_bit = 0;
}

SPI1->CR2 =
(0 << SPI_CR2_RXNEIE)
| (0 << SPI_CR2_TXDMAEN)
| (1 << SPI_CR2_SSOE);

DMA1_Channel3->CCR =
(DMA_PL_HIGH << DMA_CCR_PL) // приоритет высокий
| (DMA_SIZE_BYTE << DMA_CCR_MSIZE) // размер памяти 8-бит
| (DMA_SIZE_BYTE << DMA_CCR_PSIZE) // размер периферии 8-бит
| (1 << DMA_CCR_DIR)
| (1 << DMA_CCR_MINC) // автоинкремент памяти
| (0 << DMA_CCR_CIRC) // циклический буфер
| (0 << DMA_CCR_HTIE) // прерывание полузаполнения
| (1 << DMA_CCR_TCIE) // прерывание полного заполнения
| (0 << DMA_CCR_EN); // канал выключен

DMA1_Channel3->CPAR = SPI1_DR; // адрес периферийного регистра

DMA1_Channel3->CMAR =
(vu32)&dynamic_video_trans[DYNAMIC_VIDEO_N * dyn_cnt]; // адрес буфера в памяти
DMA1_Channel3->CNDTR = DYNAMIC_VIDEO_N; // размер буфера памяти

DMA1_Channel3->CCR =
(DMA_PL_HIGH << DMA_CCR_PL) // приоритет высокий
| (DMA_SIZE_BYTE << DMA_CCR_MSIZE) // размер памяти 8-бит
| (DMA_SIZE_BYTE << DMA_CCR_PSIZE) // размер периферии 8-бит
| (1 << DMA_CCR_DIR)
| (1 << DMA_CCR_MINC) // автоинкремент памяти
| (0 << DMA_CCR_CIRC) // циклический буфер
| (0 << DMA_CCR_HTIE) // прерывание полузаполнения
| (1 << DMA_CCR_TCIE) // прерывание полного заполнения
| (1 << DMA_CCR_EN); // канал включен

SPI1->CR2 =
(0 << SPI_CR2_RXNEIE)
| (1 << SPI_CR2_TXDMAEN)
| (1 << SPI_CR2_SSOE);

dyn_cnt++;
}
}
Quantum1
Цитата(adnega @ Aug 12 2014, 16:52) *
Не согласен, но можете поробовать. Это самый маленький пример каскадного использования сразу 4 таймеров, DMA и SPI.
К сожалению, на вопросы отвечать не готов. И стандартной библиотекой я не пользуюсь.
Пять минут пошли... )))
CODE
#ifdef TABLO_MODE_DYNAMIC2
//-----------------------------------------------------------------------------
// void __inline init_DMA1_CH6(int phase)
//-----------------------------------------------------------------------------
void __inline init_DMA1_CH6(int phase)
{
volatile int i;
// con_str("*");
// con_start();

TIM3->CR1 = 0;
TIM1->CR1 = 0;
TIM1->DIER = (0 << TIM_DIER_CC1DE);

DMA1_Channel6->CCR =
(DMA_PL_HIGH << DMA_CCR_PL) // приоритет высокий
| (DMA_SIZE_BYTE << DMA_CCR_MSIZE) // размер памяти 8-бит
| (DMA_SIZE_BYTE << DMA_CCR_PSIZE) // размер периферии 8-бит
| (1 << DMA_CCR_DIR)
| (1 << DMA_CCR_MINC) // автоинкремент памяти
| (0 << DMA_CCR_CIRC) // циклический буфер
| (0 << DMA_CCR_HTIE) // прерывание полузаполнения
| (0 << DMA_CCR_TCIE) // прерывание полного заполнения
| (0 << DMA_CCR_EN); // канал выключен

DMA1_Channel6->CPAR = SPI1_DR; // адрес периферийного регистра

DMA1_Channel6->CMAR = (vu32)&dynamic_video_trans[0]; // адрес буфера в памяти

DMA1_Channel6->CNDTR = DYNAMIC_VIDEO_SIZE; // размер буфера памяти

T1_STB_bit = 0;

DMA1->IFCR = (1 << DMA_ISR_TCIF6);
TIM1->DIER = (1 << TIM_DIER_CC1DE);
TIM1->CNT = 0;
TIM1->EGR = (1 << TIM_EGR_UG);
TIM1->SR = 0;

DMA1_Channel6->CCR =
(DMA_PL_HIGH << DMA_CCR_PL) // приоритет высокий
| (DMA_SIZE_BYTE << DMA_CCR_MSIZE) // размер памяти 8-бит
| (DMA_SIZE_BYTE << DMA_CCR_PSIZE) // размер периферии 8-бит
| (1 << DMA_CCR_DIR)
| (1 << DMA_CCR_MINC) // автоинкремент памяти
| (0 << DMA_CCR_CIRC) // циклический буфер
| (0 << DMA_CCR_HTIE) // прерывание полузаполнения
| (0 << DMA_CCR_TCIE) // прерывание полного заполнения
| (1 << DMA_CCR_EN); // канал включен

TIM15->CNT = 0;
TIM15->EGR = (1 << TIM_EGR_UG);
TIM15->CR1 =
(1 << TIM_CR1_CEN)
| (1 << TIM_CR1_OPM)
| (1 << TIM_CR1_ARPE);

TIM3->CNT = 0;
TIM3->EGR = (1 << TIM_EGR_UG);
TIM3->SR = 0;

TIM1->CR1 = (1 << TIM_CR1_CEN);
TIM3->CR1 = (1 << TIM_CR1_CEN);

TIM17->CNT = 0;
}

//-----------------------------------------------------------------------------
// void __inline init_TIMER1(void)
//-----------------------------------------------------------------------------
void __inline init_TIMER1(void)
{
TIM1->CR1 = 0;

if(rcc_state == RCC_STATE_PLL)
{
TIM1->PSC = (FPLL / FHSI) - 1;
}
else
{
TIM1->PSC = 0;
}

TIM1->ARR = (300) - 1;
TIM1->EGR = (1 << TIM_EGR_UG);

TIM1->CCR1 = 1; // импульс "DMA транзакция"
TIM1->CCER = (1 << TIM_CCER_CC1E); // импульс "DMA транзакция"
TIM1->CCMR1 = (OC_MODE_PWM1 << TIM_CCMR1_OC1M); // импульс "DMA транзакция"
TIM1->CCMR2 = 0;
TIM1->CR2 = 0;
TIM1->SMCR =
(0 << TIM_SMCR_TS) // ITR0 = TIM15
| (5 << TIM_SMCR_SMS); // GATED_MODE

TIM1->BDTR = (1 << TIM_BDTR_MOE);
TIM1->DIER = (1 << TIM_DIER_CC1DE);
}

//-----------------------------------------------------------------------------
// void __inline init_TIMER15(void)
//-----------------------------------------------------------------------------
void __inline init_TIMER15(void)
{
TIM15->CR1 = 0;
TIM15->EGR = (1 << TIM_EGR_UG);
TIM15->PSC = 0;
TIM15->ARR = 0xFFFF;
TIM15->SMCR =
(7 << TIM_SMCR_SMS) // EXTERNAL_CLOCK
| (1 << TIM_SMCR_TS); // ITR1 = TIM3

TIM15->CCR1 = (DYNAMIC_VIDEO_SIZE / DYNAMIC_VIDEO_N) + 0;

TIM15->CCER = (1 << TIM_CCER_CC1E);
TIM15->CCMR1 = (OC_MODE_PWM1 << TIM_CCMR1_OC1M);
TIM15->CCMR2 = 0;
TIM15->CR2 = (4 << TIM_CR2_MMS); // TRGO = OC1REF
TIM15->DIER = 0;
TIM15->BDTR = (1 << TIM_BDTR_MOE);
TIM15->CR1 =
(0 << TIM_CR1_CEN)
| (1 << TIM_CR1_OPM)
| (1 << TIM_CR1_ARPE);
}

//-----------------------------------------------------------------------------
// void __inline init_TIMER3(void)
//-----------------------------------------------------------------------------
void __inline init_TIMER3(void)
{
TIM3->CR1 = 0;

if(rcc_state == RCC_STATE_PLL)
{
TIM3->PSC = (FPLL / FHSI) - 1; // запись периода
TIM3->ARR = (300 * 32) - 1; // запись базы
TIM3->CCR3 = TIM3->ARR - 100; // импульс "сдвиг"
TIM3->CCR4 = TIM3->ARR - 200; // импульс "защелка"
}
else
{
TIM3->PSC = 0; // запись периода
TIM3->ARR = (300 * 32) - 1; // запись базы
TIM3->CCR3 = 1; //TIM2->ARR - 2; // импульс "сдвиг"
TIM3->CCR4 = TIM3->ARR - 1; // импульс "защелка"
}
TIM3->EGR = (1 << TIM_EGR_UG);

TIM3->CCR1 = 8; // импульс "DMA транзакция"
TIM3->CCR2 = TIM3->ARR - 200; // импульс "счет"
TIM3->CCER =
(1 << TIM_CCER_CC1E) // импульс "DMA транзакция"
| (1 << TIM_CCER_CC2E) // импульс "счет"
| (1 << TIM_CCER_CC3E) // импульс "защелка"
| (1 << TIM_CCER_CC4E); // импульс "сдвиг"

TIM3->CCMR1 =
(OC_MODE_PWM2 << TIM_CCMR1_OC1M) // импульс "DMA транзакция"
| (OC_MODE_PWM2 << TIM_CCMR1_OC2M); // импульс "счет"

TIM3->CCMR2 =
(OC_MODE_PWM2 << TIM_CCMR2_OC3M) // импульс "защелка"
| (OC_MODE_PWM2 << TIM_CCMR2_OC4M); // импульс "сдвиг"

TIM3->CR2 = (5 << TIM_CR2_MMS); // TRGO = OC2REF
TIM3->SMCR =
(2 << TIM_SMCR_TS) // ITR2 = TIM15
| (5 << TIM_SMCR_SMS); // GATED_MODE

TIM3->DIER = 0;

}

//-----------------------------------------------------------------------------
// void __inline init_TIMER16(void)
//-----------------------------------------------------------------------------
void __inline init_TIMER16(void)
{
if(rcc_state == RCC_STATE_PLL)
TIM16->PSC = (10 * FPLL / FHSI) - 1;
else
TIM16->PSC = (10) - 1;
TIM16->ARR = (800000 / FDYNAMIC_REFRESH) - 1;
TIM16->CR1 = 0;
TIM16->CCMR1 = 0;
TIM16->CCER = 0;
TIM16->SMCR = 0;
TIM16->DIER = (1 << TIM_DIER_UIE);
TIM16->BDTR = (1 << TIM_BDTR_MOE);
TIM16->CR1 = (1 << TIM_CR1_CEN);
}

//-----------------------------------------------------------------------------
// void __inline init_SPI1(void)
//-----------------------------------------------------------------------------
void __inline init_SPI1(void)
{
SPI1->CR1 =
(0 << SPI_CR1_SPE)
| (0 << SPI_CR1_DFF)
| (1 << SPI_CR1_SSM)
| (1 << SPI_CR1_SSI)
| (1 << SPI_CR1_MSTR)
| (3 << SPI_CR1_BR);

SPI1->CR2 =
(0 << SPI_CR2_RXNEIE)
| (0 << SPI_CR2_TXDMAEN)
| (1 << SPI_CR2_SSOE);

SPI1->CR1 =
(1 << SPI_CR1_SPE)
| (0 << SPI_CR1_DFF)
| (1 << SPI_CR1_SSM)
| (1 << SPI_CR1_SSI)
| (1 << SPI_CR1_MSTR)
| (3 << SPI_CR1_BR);
}
//-----------------------------------------------------------------------------
// void TIM1_TRG_COM_TIM17_IRQHandler(void)
//-----------------------------------------------------------------------------
void TIM1_TRG_COM_TIM17_IRQHandler(void) __attribute__((interrupt("IRQ")));
void TIM1_TRG_COM_TIM17_IRQHandler(void)
{
static int phase = 0;
static int dyn_cnt = 0;
int i;

if(TIM17->SR & (1 << TIM_SR_UIF))
{
TIM17->SR &= ~(1 << TIM_SR_UIF);

// DYNAMIC

for(i = 0; i < 40; i++) T1_STORE_bit = 0;

T1_STORE_bit = 1;
T1_STORE_bit = 0;

if(dyn_cnt > 7)
{
T1_STB_bit = 1;
T1_CLK_bit = 1;
T1_CLK_bit = 0;
T1_STB_bit = 0;
dyn_cnt = 0;
}
else
{
T1_CLK_bit = 1;
T1_CLK_bit = 0;
}

SPI1->CR2 =
(0 << SPI_CR2_RXNEIE)
| (0 << SPI_CR2_TXDMAEN)
| (1 << SPI_CR2_SSOE);

DMA1_Channel3->CCR =
(DMA_PL_HIGH << DMA_CCR_PL) // приоритет высокий
| (DMA_SIZE_BYTE << DMA_CCR_MSIZE) // размер памяти 8-бит
| (DMA_SIZE_BYTE << DMA_CCR_PSIZE) // размер периферии 8-бит
| (1 << DMA_CCR_DIR)
| (1 << DMA_CCR_MINC) // автоинкремент памяти
| (0 << DMA_CCR_CIRC) // циклический буфер
| (0 << DMA_CCR_HTIE) // прерывание полузаполнения
| (1 << DMA_CCR_TCIE) // прерывание полного заполнения
| (0 << DMA_CCR_EN); // канал выключен

DMA1_Channel3->CPAR = SPI1_DR; // адрес периферийного регистра

DMA1_Channel3->CMAR =
(vu32)&dynamic_video_trans[DYNAMIC_VIDEO_N * dyn_cnt]; // адрес буфера в памяти
DMA1_Channel3->CNDTR = DYNAMIC_VIDEO_N; // размер буфера памяти

DMA1_Channel3->CCR =
(DMA_PL_HIGH << DMA_CCR_PL) // приоритет высокий
| (DMA_SIZE_BYTE << DMA_CCR_MSIZE) // размер памяти 8-бит
| (DMA_SIZE_BYTE << DMA_CCR_PSIZE) // размер периферии 8-бит
| (1 << DMA_CCR_DIR)
| (1 << DMA_CCR_MINC) // автоинкремент памяти
| (0 << DMA_CCR_CIRC) // циклический буфер
| (0 << DMA_CCR_HTIE) // прерывание полузаполнения
| (1 << DMA_CCR_TCIE) // прерывание полного заполнения
| (1 << DMA_CCR_EN); // канал включен

SPI1->CR2 =
(0 << SPI_CR2_RXNEIE)
| (1 << SPI_CR2_TXDMAEN)
| (1 << SPI_CR2_SSOE);

dyn_cnt++;
}
}


это разве самый маленький пример? знать бы еще для начала какой таймер куда... т.е. хотя бы что там каждый таймер делает.. тем более что комментариев там практически нет... да и мне полезны из этого примеры на максимум 5-6 строчек, если не меньше*))


Раз уж вы так хотите пины*)) без проблем... берем TIM1 - он будет ведущим, каждые 500мкс при CNT=CCR1, он инициирует один запуск TIM3_CH1(длительность импульса 40мкс, выводится на PA6) и TIM3_CH2(длительность импульса 5мкс, выводится на PA7).
Golikov A.
почему всегда все так сложно?
я скачал реф мануал от 32f103c6, и в нем поглядел раздел таймеры. И там очень быстро нашел ссылку как сделать один таймер запускателем второго
Using one timer to enable another timer, страница 392.
куда уж лучшие примеры? Там и описано все по шагам чего куда настроить и так далее... Ну да без библиотек идиотских с кучей функций перекрывающих друг друга, зато по сути, настроил регистры так, эти сяк, этот досчитал, эти поехали...

adnega
Цитата(Quantum1 @ Aug 13 2014, 09:00) *
Раз уж вы так хотите пины*)) без проблем... берем TIM1 - он будет ведущим, каждые 500мкс при CNT=CCR1, он инициирует один запуск TIM3_CH1(длительность импульса 40мкс, выводится на PA6) и TIM3_CH2(длительность импульса 5мкс, выводится на PA7).

Т.е. процесс должен быть периодическим, или нужен ручной запуск однократной последовательности?
Это для периодической генерации
CODE
TIM1->CR1 = 0;
TIM1->CR2 = (4 << TIM_CR2_MMS); // OC1REF -> TRGO
TIM1->PSC = 72 - 1;
TIM1->ARR = 500 - 1;
TIM1->EGR = (1 << TIM_EGR_UG);
TIM1->CCMR1 = (OC_MODE_PWM2 << TIM_CCMR1_OC1M);
TIM1->CCER = (1 << TIM_CCER_CC1E);
TIM1->BDTR = (1 << TIM_BDTR_MOE);
TIM1->CCR1 = 100;

TIM3->CR1 = 0;
TIM3->PSC = 72 - 1;
TIM3->ARR = 0xffff;
TIM3->EGR = (1 << TIM_EGR_UG);
TIM3->CCMR1 = (OC_MODE_PWM1 << TIM_CCMR1_OC1M) | (OC_MODE_PWM1 << TIM_CCMR1_OC2M);
TIM3->CCER = (1 << TIM_CCER_CC1E) | (1 << TIM_CCER_CC2E);
TIM3->SMCR =
(0 << TIM_SMCR_TS) // TRGI -> ITR0 (TIM1)
| (4 << TIM_SMCR_SMS); // Reset Mode

TIM3->CCR1 = 40;
TIM3->CCR2 = 5;
TIM3->CR1 = (1 << TIM_CR1_CEN);

TIM1->CR1 = (1 << TIM_CR1_CEN);


Для однократного запуска

CODE
// pulse
TIM1->CR1 = 0;
TIM1->CR2 = (4 << TIM_CR2_MMS); // OC1REF -> TRGO
TIM1->PSC = 72 - 1;
TIM1->ARR = 500 - 1;
TIM1->EGR = (1 << TIM_EGR_UG);
TIM1->CCMR1 = (OC_MODE_PWM2 << TIM_CCMR1_OC1M);
TIM1->CCER = (1 << TIM_CCER_CC1E);
TIM1->BDTR = (1 << TIM_BDTR_MOE);
TIM1->CCR1 = 100 - 1; // на один такт меньше

TIM3->CR1 = 0;
TIM3->PSC = 72 - 1;
TIM3->ARR = 0xffff;
TIM3->EGR = (1 << TIM_EGR_UG);
TIM3->CCMR1 = (OC_MODE_PWM1 << TIM_CCMR1_OC1M) | (OC_MODE_PWM1 << TIM_CCMR1_OC2M);
TIM3->CCER = (1 << TIM_CCER_CC1E) | (1 << TIM_CCER_CC2E);
TIM3->SMCR =
(0 << TIM_SMCR_TS) // TRGI -> ITR0 (TIM1)
| (5 << TIM_SMCR_SMS); // Gated Mode

TIM3->CCR1 = 40;
TIM3->CCR2 = 5;
TIM3->CR1 = (1 << TIM_CR1_CEN);

while(1)
{
if(pulse)
{
TIM3->CNT = 0xffff; // -1 для генерации события UR
TIM1->CR1 = (1 << TIM_CR1_CEN) | (1 << TIM_CR1_OPM);
pulse = 0;
}
}


Проверено в железе (STM32F103T8U6 @ 72MHz) - работает.

Цитата(Golikov A. @ Aug 13 2014, 10:30) *
почему всегда все так сложно?
я скачал реф мануал от 32f103c6, и в нем поглядел раздел таймеры. И там очень быстро нашел ссылку как сделать один таймер запускателем второго
Using one timer to enable another timer, страница 392.
куда уж лучшие примеры? Там и описано все по шагам чего куда настроить и так далее... Ну да без библиотек идиотских с кучей функций перекрывающих друг друга, зато по сути, настроил регистры так, эти сяк, этот досчитал, эти поехали...

Там есть тонкости в работе ШИМ для однокрытного запуска. По сути при сработке UR (досчитал до конца) уровень ШИМ выставляется, при достижении сравнения - снимается.
Так вот, когда таймер стартует UR не происходит, а выставляется уровень только после окончания счета (CNT > ARR). Это надо прочувствовать))
AHTOXA
Цитата(adnega @ Aug 13 2014, 13:22) *
Код
...
    TIM1->BDTR = (1 << TIM_BDTR_MOE);
...

Глаз споткнулся на вашем примере. В stm32f10x.h TIM_BDTR_MOE определён как 0x8000. (1 << 0x8000) = 0. И так во всём вашем коде.
Вы переопределили все маски в номера битов что ли?
adnega
Цитата(AHTOXA @ Aug 13 2014, 13:29) *
Глаз споткнулся на вашем примере. В stm32f10x.h TIM_BDTR_MOE определён как 0x8000. (1 << 0x8000) = 0. И так во всём вашем коде.
Вы переопределили все маски в номера битов что ли?

Ага. Я в define указываю номера битов.
AHTOXA
С тем же именем, что и у маски в stm32f10x.h? Вы прямо этот файл переделали?
Кстати, аккуратнее писать (1UL << BIT_NUM), чтобы не иметь проблем со старшим битом.
Golikov A.
жестоко штатный хедер переписать под свой стильsm.gif....

при сдвиге влево вроде как пофиг на старший бит, гораздо важнее что L - то есть лонг, а то найдется компилятор который 16 бит по умолчанию делает, и при сдвиге дальше 16 все обнулится...
хотя после всей этой пляски с битностью инта перехожу на явные типы (((uint32_t) 0x01) << SHIFT)
AHTOXA
Цитата(Golikov A. @ Aug 13 2014, 23:44) *
при сдвиге влево вроде как пофиг на старший бит, гораздо важнее что L

Нет, не пофиг. По умолчанию будет int. И при сдвиге int-а на 31 влево получится фигня.

Цитата(Golikov A. @ Aug 13 2014, 23:44) *
хотя после всей этой пляски с битностью инта перехожу на явные типы (((uint32_t) 0x01) << SHIFT)

1UL тоже явный тип. И выглядит поприличнее, чем приведение типа. ИМХО конечно.
Golikov A.
хм... надо проверить, мне кажется фигни не должно быть, но не утверждаю...

Long - не есть явный тип, там где int16 он 32, а где int32 - он 64. А сейчас 64 битные процессоры набирают обороты, того и гляди в 128 бит перейдет. В приведенном типе мне нравиться что битность указана явно 32 как бы он не называлсяsm.gif запись длиннее, факт, но 100% определена.
AHTOXA
Цитата(Golikov A. @ Aug 14 2014, 02:23) *
Long - не есть явный тип, там где int16 он 32, а где int32 - он 64. А сейчас 64 битные процессоры набирают обороты, того и гляди в 128 бит перейдет. В приведенном типе мне нравиться что битность указана явно 32 как бы он не называлсяsm.gif запись длиннее, факт, но 100% определена.

Можете привести пример, когда вам не хватит ширины константы 1UL? sm.gif
adnega
Уважаемые, тут недалеко есть аж два топика, где обсуждаются маски, библиотеки и биты)) (я сам там читатель)
Для запуска каскадной работы таймеров это рояля не играет - запустить можно, пример конфигурации привел.
ТС самостояельно перепишет все как положено в SPL.
Quantum1
спасибо огромное, сегодня попробую разобраться
Golikov A.
Цитата
Можете привести пример, когда вам не хватит ширины константы 1UL?

наверное не смогу... может через 100 лет для каких-то машин где будет тип экстралонг... я лично уверен что мои программы проработают не меньшеsm.gif...

кстати проверил
((int32_t)1 << 31) - все честно, получаем минус максимум, или 0x80000000, а дальше нули, никаких неожиданностей если мы используем это как маску, если как число, то очевидное переполнение, что тоже ожидаемо.
AHTOXA
Цитата(Golikov A. @ Aug 14 2014, 11:54) *
наверное не смогу... может через 100 лет для каких-то машин где будет тип экстралонг... я лично уверен что мои программы проработают не меньшеsm.gif...

Ну, для экстралонга явное (uint32_t) тем более не поможетsm.gif
Цитата(Golikov A. @ Aug 14 2014, 11:54) *
кстати проверил
((int32_t)1 << 31) - все честно, получаем минус максимум, или 0x80000000, а дальше нули, никаких неожиданностей если мы используем это как маску, если как число, то очевидное переполнение, что тоже ожидаемо.

Да, сейчас тоже не смог получить ошибочный результат. Но помню, что какие-то проблемы были. Так что лучше буду страховаться.

Цитата(adnega @ Aug 14 2014, 03:00) *
Уважаемые, тут недалеко есть аж два топика, где обсуждаются маски, библиотеки и биты)) (я сам там читатель)

Всё, всё, уходим wink.gif
Golikov A.
уходя крикну в закрывающуюся дверьsm.gif

проблемы со сдвигом в права
(0x80 >> 1)
если компилятору стукнет что это знаковый тип, то вместо ожидаемых 0x40 будет 0xC0
а если его по какой то причине зарубит сделать арифметический сдвиг для знакового
то 0x81 может переделать в 0xC1. но как добиться последнего я не очень в курсе, это если попросить разделить на 2, то он так может сделать....

но на самом деле букв в компутере дофига, и лишние UL никому не помешаютsm.gif
KRS
Цитата(Golikov A. @ Aug 14 2014, 00:23) *
Long - не есть явный тип, там где int16 он 32, а где int32 - он 64. А сейчас 64 битные процессоры набирают обороты, того и гляди в 128 бит перейдет.

вы бы лучше стандарт почитали!
например на win64 и int и long остались 32 битными! а вот size_t и int_ptr_t уже 64 битные.


Цитата
проблемы со сдвигом в права
(0x80 >> 1)
если компилятору стукнет что это знаковый тип,

в данном случае не стукнет, по многим причинам. смотрите стандарт sm.gif
Golikov A.
а вы только под win пишите?
и как называется 64 битный целый тип?
какой из стандартов вы предлагаете читать?
это был гипотетический пример, потому что было лень писать много нулей
KRS
Цитата(Golikov A. @ Aug 17 2014, 08:53) *
а вы только под win пишите?
и как называется 64 битный целый тип?
какой из стандартов вы предлагаете читать?
это был гипотетический пример, потому что было лень писать много нулей

не только! а win привел как пример того что разрядность целого типа слабо зависит от разрядности процессора! Для 64 битного линукса кстати long - 64 битный.
64 битный целый тип на сегодня - long long, но лучше конечно использовать stdint.h
стандарт - С99 например, или новый С11
про пример - я же писал по многим причинам! одна из них - шестнадцатеричные константы считаются unsigned.
Golikov A.
ну так и я о том же...
если написано int32_t - то это 32 бита очевидно, понятно, предсказуемо. А если long или int - то тут как повезет...

в остальном, возможно я уже дую на воду, но тема не об этом...
adnega
Цитата(Golikov A. @ Aug 17 2014, 18:02) *
в остальном, возможно я уже дую на воду, но тема не об этом...

Может, нужно создать тему на эту (типы данных) тему?
Я б накидал вопросов на подумать в такой ветке))
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.