Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F103C8T - перезапуск таймера от внешнего сигнала
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
varvar
Пытаюсь перенести на STM32 свой старый проект на MSP430. И второй день туплю с применением таймера.
Делаю OSD. Алгоритм простой - на ногу 10 (PA0) подключен HSYNC. От него должен запустится таймер (TIM2) и запустить через какое-то время DMA и вызвать прерывание. Хотелось бы все сделать с минимумом кода, момент запуска DMA должен быть точно привязан к HSYNC, иначе изображение будет дергаться.
Задом чуствую, как-то надо использовать one pulse mode, но не выходит каменный цветок sad.gif
Прошу помощи более опытных товарищей - с STM32 я только начал играться. Ткните носом в пример кода инициализации таймера sm.gif

kolobok0
Цитата(varvar @ Mar 27 2016, 12:04) *
...Ткните носом в пример кода инициализации таймера sm.gif


Не буду оригинален, на сайте производителя смотрели всевозможные библиотеки с примерами или просто примеры?
В кубе были по мойму примеры генерации подобных вещей.

(круглый)
scifi
Можно и по старинке - почитать мануал, понять, как всё это работает... Или это нынче не модно?
varvar
Спасибо на добром слове, вот такая заготовка заработала:
CODE
void hsync_timer_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

/* Time base configuration */
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 100;
TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

/* TIM2 PWM2 Mode configuration: Channel1 */
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 20;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);

/* TIM2 configuration in Input Capture Mode */

TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);

/* One Pulse Mode selection */
TIM_SelectOnePulseMode(TIM2, TIM_OPMode_Single);
/* Input Trigger selection */
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
/* Slave Mode selection: Trigger Mode */
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Trigger);
//TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE)
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);

TIM_Cmd(TIM2, ENABLE);
NVIC_EnableIRQ(TIM2_IRQn);
}

void TIM2_IRQHandler(void)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
SPI1->DR |= 0xCCCC;
SPI2->DR |= 0x3333;
}


Понять бы почему, мне кажется, что

TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);

не в тему, должно быть TIM_TS_TI1FP1

А куб, конечно, хорошая вещь, когда памяти немеряно и спешить некуда. Ну и не удалось мне совместить HAL с scmRTOS.
AleksBak
Цитата(varvar @ Mar 27 2016, 15:51) *
...Ну и не удалось мне совместить HAL с scmRTOS.

А scmRTOS Вы раньше использовали и теперь хотите использовать я так понял? Я вот на днях, благодаря участнику esaulenka, обнаружил, что оказывается есть много библиотек и софта (esaulenka писал конкретно о stm32tpl) Участника данного форума - АНТОХА кажется его никнейм точно сейчас не помню и у него есть портированная эта ОС тоже. Человек сделал большую работу и выложил ее для всеобщего доступа.
varvar
scmRTOS чудесно работает с CMSIS, а куб генерирует HAL. У меня не получилось заставить вместе работать кубовый USB стек и scmRTOS.
Хотя может быть и к лучшему - HAL память жрет, как свинья помои.
AleksBak
Цитата(varvar @ Mar 28 2016, 12:19) *
scmRTOS чудесно работает с CMSIS, а куб генерирует HAL...

Хм.. Значит Вы же попробовали/проверили эту ОС на этом контроллере. А я думал, что нет..
Цитата(varvar @ Mar 28 2016, 12:19) *
...
Хотя может быть и к лучшему - HAL память жрет, как свинья помои.

А где именно Вы нашли, что много памяти он жрет? Я спрашиваю это потому, что сам такой же новичок в АРМ-ах хотя уже лет 20 (двадцать) контроллерами занимаюсь. То что HAL много "лишних" движений делает - это понятно. Т.к. задумка для него была сделать универсальность еще. То что бывают неучтенные баги и недочеты для конкретного контроллера - это тоже понятно (опять-таки из-за универсальности). То что есть некоторые сильно "кривые" моменты - тоже понятно. Но про жрание памяти пока не знал. Память программ Вы может имели ввиду? А не ОЗУ как я понял? Это да, но ведь это не просто использование памяти, а использование памяти кодом (хоть и кривым/растянутым, но готовым уже и вместо вашего он уже есть). Еще можно отключить некоторые вещи в Cube для экономии памяти (Full Assert и т.п.). А еще, у человека про которого я написал и одного из разработчиков/писателей этой scmRTOS (АНТОХА) есть также свой фреймворк как альтернатива HAL-у. Может его попробуете? Попробуете его потом наверно все-таки т.к. сейчас основная проблема - это разобраться вначале с работой периферии (Таймера и пр.) - тут, у стм-овских контроллеров, она гораздо сложнее.
varvar
Цитата(AleksBak @ Mar 28 2016, 12:30) *
А где именно Вы нашли, что много памяти он жрет?

На собственном грустном опыте - у MSP430 стек отъел меньше 8к памяти - у STM в районе 20. scmRTOS не пошла - пришлось ставить FreeRTOS - еще 10 кбайт долой, плюс оперативку хорошо подъела. Короче, FreeRTOS, USB, IMU и дисплей - 60к долой. Аналогичная задача на MSP заняла меньше 20к. Ну и сложность периферии - это смотря с чем сравнивать. По-моему у MSP430 периферия посложнее будет, но есть хорошие примеры, которые снимают все вопросы.
Кстати, то же OSD на MSP430 мне удавалось сделать использую около 200 байт оперативки для видео буферов sm.gif
Цитата(AleksBak @ Mar 28 2016, 12:30) *
хотя уже лет 20 (двадцать) контроллерами занимаюсь.

Ну Вы еще совсем молодой, у Вас все впереди sm.gif
AleksBak
Цитата(varvar @ Mar 28 2016, 13:51) *
На собственном грустном опыте - у MSP430 стек отъел меньше 8к памяти - у STM в районе 20...

Да - большая разница (хотя все-равно не понятно откуда там так много - 20К, но все равно это не так важно). Еще по именно Вашей теме напишу такую вещь - HAL как бы вводит понятия уже более "сложного" программирования и у него есть такие полезные вещи как callback-и и тут они пригодились бы. Но Вы пишите про использование FreeRTOS (и еще Вам важно быстродействие системы), то тогда это про как информация пусть будет.
Tarbal
Цитата(varvar @ Mar 27 2016, 13:04) *
Пытаюсь перенести на STM32 свой старый проект на MSP430. И второй день туплю с применением таймера.
Делаю OSD. Алгоритм простой - на ногу 10 (PA0) подключен HSYNC. От него должен запустится таймер (TIM2) и запустить через какое-то время DMA и вызвать прерывание. Хотелось бы все сделать с минимумом кода, момент запуска DMA должен быть точно привязан к HSYNC, иначе изображение будет дергаться.
Задом чуствую, как-то надо использовать one pulse mode, но не выходит каменный цветок sad.gif
Прошу помощи более опытных товарищей - с STM32 я только начал играться. Ткните носом в пример кода инициализации таймера sm.gif


Я бы сделал следующим образом:
Подключить строчный синхроимпульс ко входу input capture свободно бегущего таймера.
В обработчике прерывания input capture прибавил к захваченному значению требуемое время задержки в тиках таймера (h front porch) и записал полученную сумму в compare register для output compare того же таймера. В обработчике прерывания output compare запускать DMA.
Если не все понятно -- могу углубиться в детали.
varvar
Цитата(Tarbal @ Mar 28 2016, 17:05) *
Я бы сделал следующим образом:
Подключить строчный синхроимпульс ко входу input capture свободно бегущего таймера.
В обработчике прерывания input capture прибавил к захваченному значению требуемое время задержки в тиках таймера (h front porch) и записал полученную сумму в compare register для output compare того же таймера. В обработчике прерывания output compare запускать DMA.
Если не все понятно -- могу углубиться в детали.

Примерно так кода-то делал - на другом процессоре - наложенное изображение дергается, немного, но неприятно. А когда таймер, запускаемый от hsync автоматически запускает DMA безо всяких прерываний - получается абсолютно стабильная картинка. Теоретически и STM32 должно быть то же самое - но пока у меня DMA от таймера запускается - но со временем какая-то беда, что-то не так настраиваю. В примере от ST пишут, что используется CCR1, а что-то непонятное они делают с CCR2 (/Project/STM32xx_StdPeriph_Examples/TIM/OnePulse folder.)
В принципе, эта идея вролне совместима с Вашей - вполне можно вместо вызова прерываний запустить DMA, если мой вариант не сработает - попробую Ваш.
jcxz
Цитата(varvar @ Mar 28 2016, 15:51) *
На собственном грустном опыте - у MSP430 стек отъел меньше 8к памяти - у STM в районе 20. scmRTOS не пошла - пришлось ставить FreeRTOS - еще 10 кбайт долой, плюс оперативку хорошо подъела. Короче, FreeRTOS, USB, IMU и дисплей - 60к долой.

Что-то это как-то слишком - 60К под такую простую задачу.
Вот у меня сейчас открыт в чём-то похожий проект на Cortex-M: uCOS + USB + SPI-LCD (своя графика: прямые, прямоугольники, треугольники, текст, ...) + АЦП + прочие мелочи.
Всё в сумме: 29704 (ro code) + 20216 (ro data), причём "ro data" - это в основном шрифты и пиктограммы. Так что, если не считать шрифтов, флеши наберётся на <30К. Да и то из них там много лишнего - MassStorage в USB который там болтается, но пока не используется. Если его да всякую отладку повыкидывать - будет наверное чуть больше 20кил. Ваш проект ещё меньше флеши должен занять.
А стек Вы сами выделяете, раз сами выделили 20, вот он столько и съел. Выделяйте меньше.
varvar
Цитата(jcxz @ Mar 28 2016, 19:35) *
Всё в сумме: 29704 (ro code) + 20216 (ro data), причём "ro data" - это в основном шрифты и пиктограммы. Так что, если не считать шрифтов, флеши наберётся на <30К. Да и то из них там много лишнего - MassStorage в USB который там болтается, но пока не используется. Если его да всякую отладку повыкидывать - будет наверное чуть больше 20кил.

И все это с кубовым USB и HAL? Что компилятор может настолько разный размер генерить - не очень похоже (в моем случае GCC).
Без HAL размеры несколько скромнее.

jcxz
Цитата(varvar @ Mar 28 2016, 22:48) *
И все это с кубовым USB и HAL?

Нет конечно, такое гумно не использую. USB-стек из примеров IAR, остальное (кроме uCOS) - своё.
Tarbal
Цитата(varvar @ Mar 28 2016, 19:27) *
Примерно так кода-то делал - на другом процессоре - наложенное изображение дергается, немного, но неприятно. А когда таймер, запускаемый от hsync автоматически запускает DMA безо всяких прерываний - получается абсолютно стабильная картинка. Теоретически и STM32 должно быть то же самое - но пока у меня DMA от таймера запускается - но со временем какая-то беда, что-то не так настраиваю. В примере от ST пишут, что используется CCR1, а что-то непонятное они делают с CCR2 (/Project/STM32xx_StdPeriph_Examples/TIM/OnePulse folder.)
В принципе, эта идея вролне совместима с Вашей - вполне можно вместо вызова прерываний запустить DMA, если мой вариант не сработает - попробую Ваш.


Вам надо найти если возможно заускать DMA по таймеру или output compare -- тогда и предложенный мной способ будет безупречен sm.gif.

В моем предложении задержка с прерыванием, запускающим DMA может привести к дерганью картинки. Но всегда можно найти способ улучшить. Навскидку:
поставить прерывание на время перед окончанием front porch и запретить все остальные прерывания, разрешив их после старта DMA.
Второй вариант -- остальные процессы делать без прерываний, либо синхронизировать с hsync, избегая опасного участка -- момента окончания front porch.
Третий вариант -- делать ожидание окончания front porch чуть короче и выжигать время в цикле внутри прерывания.
Задержка с input capture interrupt пофиг. Там железо захватывает значение в регистр.

Цитата(jcxz @ Mar 28 2016, 20:58) *
Нет конечно, такое гумно не использую. USB-стек из примеров IAR, остальное (кроме uCOS) - своё.


Я с кубовым подхожу к окончанию проекта. Нареканий нет.
jcxz
Цитата(Tarbal @ Mar 29 2016, 00:38) *
Я с кубовым подхожу к окончанию проекта. Нареканий нет.

Нарекание уже хотя-бы то, что он монструозен, раздувает код до неприличных размеров.
Tarbal
Та мода, что вы описали есть в STM32F429. В описании (RM0090 Reference manual) глава 15.3.14 Timers and external trigger synchronization
Я не смотрел для вашего процессора. Может быть тоже есть.

Цитата(jcxz @ Mar 29 2016, 03:53) *
Нарекание уже хотя-бы то, что он монструозен, раздувает код до неприличных размеров.


Мне пофиг пока хватает места.
Tarbal
Ну что у вас? Получилось?
varvar
Цитата(Tarbal @ Apr 1 2016, 18:15) *
Ну что у вас? Получилось?

да, получилось. Картинка, как влитая. Ноги, правда, пришлось другие использовать.
Программа не особо чищена, но все работает. Нужна инициализация, дальше все прерывания делают. Буфера на страницу нет - слишком мало оперативки у процессора, только 20к. Изображение формируется "на лету", белое и черное.
CODE
#define FirstLine 30
#define LastLine 255
#define VIDEO_DELAY 820
#define VIDEO_EXRA_DELAY 400
//#define VIDEO_EXRA_DELAY 1000


uint16_t TestFlag=0x3333;
uint16_t LineCnt=0;
uint16_t LinePointer=0;
uint16_t Vsync_delay;

union buff_t
{
uint16_t wData[26];
uint8_t bData[52];
};


buff_t WhiteBuffer1;
buff_t WhiteBuffer2;
buff_t BlackBuffer1;
buff_t BlackBuffer2;

void OSD_init(void)
{


GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
SPI_InitTypeDef SPI_InitStructure;
DMA_InitTypeDef DMA_InitStructure;


for (int i=0; i<26; i++)
{
WhiteBuffer1.wData[i]= ~0x4040;
BlackBuffer1.wData[i]= ~0x0004;

// WhiteBuffer1[i]= ((i+1)<<8) +i +1;
// BlackBuffer1[i]= ((i+1)<<8) +i +1;

WhiteBuffer2.wData[i]= ~0x0040;
BlackBuffer2.wData[i]= ~0x0404;
}


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Enable GPIO Peripheral clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // for Interrupt
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // timer
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); // SPI1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // Enable DMA1 clock




// Configure test pin in output push/pull mode
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

// ****************************************************
// Vsync pin
// ****************************************************
// pin as input
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// interrupt from Vsync
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
EXTI_ClearITPendingBit(EXTI_Line3);// Clear EXTI Line Pending Bit
// Connect EXTI
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);
// Configure EXTI1 to generate an interrupt on falling edge
EXTI_InitStructure.EXTI_Line = EXTI_Line3;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);

// ****************************************************
// Hsync timer
// ****************************************************
// pin as input
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//
TIM_TimeBaseStructure.TIM_Period = VIDEO_DELAY + VIDEO_EXRA_DELAY;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// TIM2 PWM2 Mode configuration: Channel1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
TIM_OCInitStructure.TIM_Pulse = VIDEO_DELAY;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
//
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
//
TIM_SelectOnePulseMode(TIM2, TIM_OPMode_Single);
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Trigger);
//
NVIC_EnableIRQ(TIM2_IRQn);

// ****************************************************
// SPI as black and white video
// ****************************************************
// SPI1 slave (black) PA6-MISO PA5-SCK
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx ;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
SPI_InitStructure.SPI_CRCPolynomial = 10; // !!! mandatory!!!
SPI_Init(SPI1, &SPI_InitStructure);
// SPI2 master (white) PB15-MISO PB13-SCK
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx ;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_CRCPolynomial = 10; // !!! mandatory!!!
SPI_Init(SPI2, &SPI_InitStructure);
//
// ****************************************************
// DMA
// ****************************************************
// Configure DMA1 - Channel5== (memory -> SPI)

DMA_DeInit(DMA1_Channel3); //Set DMA registers to default values
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR; //Address of peripheral the DMA must map to
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BlackBuffer1.wData; //Variable from which data will be transmitted
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 26; //Buffer size
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); //Initialize the DMA
//
// master SPI black
DMA_DeInit(DMA1_Channel5); //Set DMA registers to default values
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; //Address of peripheral the DMA must map to
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)WhiteBuffer1.wData; //Variable from which data will be transmitted
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 26; //Buffer size
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_Channel5, &DMA_InitStructure); //Initialize the DMA

DMA_Cmd(DMA1_Channel3, ENABLE); // slave TX
//
//DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);


NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);



// ****************************************************
// enables
// ****************************************************
SPI1->CR2 |= 0x02; // TX DMA Enable
SPI2->CR2 |= 0x02;

}


// Vsync interrupt
extern "C" void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line3);
if (Vsync_delay > 0)
{
if (--Vsync_delay==0)
{
SPI2->CR1 |= 0x0040; // master SPI enable
SPI1->CR1 |= 0x0040; // slave SPI enable
TIM2->DIER |= TIM_DIER_CC1IE | TIM_DIER_CC1DE; // Capture/Compare 1 DMA request and interrupt enable
TIM2->CR1 |= 0x0001; // enabled
}
}
LineCnt=0;
LinePointer=0;
}
}


// Hsync interrupt
// master 5ch DMA SPI2
extern "C" void TIM2_IRQHandler(void)
{
TIM2->SR &= ~TIM_IT_CC1; // Clear CC1IF
if ((LineCnt > FirstLine) && (LineCnt < LastLine))
{
TIM2->CR1 &= ~0x0001; // timer disabled

//GPIOA->ODR |= 0x04;

TIM2->DIER &= ~TIM_DIER_CC1DE; // DMA TIM disabled
SPI2->CR2 |= 0x02; // DMA master enabled

DMA1_Channel5->CCR |= DMA_CCR5_EN | DMA_CCR5_TCIE; // enable DMA & int
LinePointer++;
}
if (LineCnt == FirstLine)
{
DMA1_Channel5->CCR |= DMA_CCR5_EN | DMA_CCR5_TCIE; // enable DMA & int
DMA1_Channel3->CCR |= DMA_CCR3_EN;
}
LineCnt++;
}

// master DMA IRQ
extern "C" void DMA1_Channel5_IRQHandler(void)
//void DMA1_Channel5_IRQHandler(void)
{
DMA1->IFCR = DMA_IFCR_CGIF5; // clear int flag

DMA1_Channel5->CCR &= ~(DMA_CCR5_EN | DMA_CCR5_TCIE); // disable DMA & interrupt
DMA1_Channel3->CCR &= ~DMA_CCR3_EN;

SPI2->CR2 &= ~0x02; // DMA master disabled
SPI1->SR &= ~SPI_I2S_FLAG_TXE; // Clear slane SPI TX INT
SPI1->CR2 |= 0x80; // slave SPI interrupt enable
}

// slave SPI IRQ
extern "C" void SPI1_IRQHandler(void)
{
SPI1->SR &= ~SPI_I2S_FLAG_TXE; // Clear SPI2 TX INT
SPI1->CR2 &= ~0x80; // SPI1 interrupt disable

//GPIOA->ODR &= ~0x04;


TIM2->SR &= ~ TIM_SR_CC1OF; // compare flag
TIM2->EGR &= ~ TIM_EGR_CC1G; // capture/compare 1 generation
TIM2->DIER |= TIM_DIER_CC1DE; // DMA TIM enabled
SPI2->CR2 &= ~0x02; // DMA SPI1 disabled

if (LineCnt != LastLine)
{
if(LineCnt & 0x01)
{
DMA1_Channel5->CMAR = (uint32_t)WhiteBuffer1.wData;
DMA1_Channel3->CMAR = (uint32_t)BlackBuffer1.wData;
}
else
{
DMA1_Channel5->CMAR = (uint32_t)WhiteBuffer2.wData;
DMA1_Channel3->CMAR = (uint32_t)BlackBuffer2.wData;
}
DMA1_Channel5->CCR |= DMA_CCR5_EN; // enable DMA
DMA1_Channel3->CCR |= DMA_CCR3_EN;
flag |= 0x01;
}
else flag |= 0x02;
TIM2->CR1 |= 0x0001; // timer enabled

}


Tarbal
Ну и хорошо sm.gif
Огурцов
почему бы не использовать spi в режиме slave, дёргать nss строчным синхроимпульсом и заполнять через dma ?
минус таймер, плюс всё чисто аппаратно
varvar
Цитата(Огурцов @ Apr 3 2016, 21:09) *
почему бы не использовать spi в режиме slave, дёргать nss строчным синхроимпульсом и заполнять через dma ?
минус таймер, плюс всё чисто аппаратно

Так, собственно и так практически все аппаратно - прерывания только меняют режимы и переключают буфера.
Таймер запускается от синхроимпульса, аппаратно при срабатывании запускает DMA, тот пишет в SPI. SPI использованы оба - один для белого, второй для черного. Ваша идея очень хороша, конечно, но программа уже как-то работает, трогать не хочется.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.