Цитата(Golikov A. @ Jul 28 2015, 18:45)

вы в какой среде пишите? Если в Keil, то для переноса функций в РАМ, вам надо правой кнопкой в С файл с функциями тыкнуть, и сказать чтобы они запустились из РАМ, все остальное сделает кеил за вас сам.
Регистры FPU надо сохранять в стэк, только если в прерываниях вы будите использовать модуль FPU, если нет, то пусть они лежат где лежать, и вход будет быстрее в прерывание и проблем не будет.
Идея с ДМА вам видится не верно.
Простите за долгое отсутствие - текучка и изучение мануала по наводке jcxz. Оказывается, я многое упустил в своё время...
Среда у меня, к сожалению, CooCox. Keil прекрасная штука, но мне не по карману, а программа слишком велика для бесплатной версии.
В прерываниях FPU нигде не используется, только в фоне. Ищу способ запретить сохранять FPU регистры в стек - а их там 32, если не ошибаюсь. Если даже по 1 такту на каждого - это уже масштаб моих флуктуаций!
Идея с DMA мною не отброшена. Я её проработаю, но позже. А пока мне надо научиться отключать Lazy context save - я даже это ещё не могу заставить сделать свой кокос.
Цитата(bugdesigner @ Jul 28 2015, 19:26)

А можно одно уточнение? У Вас таймер считает импульсы 84 МГц без прескалера? Я правильно понял?
Не могли бы Вы показать в студию код обработчика прерывания и код инициализации таймера? Может что-то прояснится...
И последнее, я присоединюсь к мнению коллег насчёт дернуть ногой при входе в обработчик. Может всё же какая-то логическая ошибка закралась.
Да, таймер считает без прескалера. Инициализируеется так:
Код
/*------------------Инициализация TIM6 - строчный таймер-*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //включаем тактирование
//Частота шины APB1 42 МГц, на таймер - 84 Мгц
TIM6->PSC = 0; //Настройка предделителя на 84 "такта" в микросекунду
TIM6->ARR = 10080; //10080 период - почти две строки 120 мкс 5600
TIM6->DIER &= ~TIM_DIER_UIE; //запрет прерывания от таймера
TIM6->CR1 |= TIM_CR1_CEN; //включаем таймер - пусть молотит непрерывно
// прерывания от TIM6 не будет
//TIM6_CNT — текущее значение счётчика для чтения/записи;
Описал максимально подробно.
Из обработчика приведу фрагмент, который, собственно и занимается выводом телевизионной строки
Код
Tim6_Count = TIM6->CNT; //длительность предыдущей строки
TIM6->CNT = 0; //начало измерения строк - сбрасываем таймер
//подготовимся к скоростному выводу данных
Td = Tdelt; //1 шаг = 10 тактов TIM6 - шаг
Ts = T_Nath - Td;//начальная задержка 10,5 мкс
Kt = KolBytStr; //число байт в строке
//Начали вывод активной строки. Пока не кончится активная строка, не выйдем отсюда
if (Zerkalo) { //вывод "зеркально" - со старшего полубайта последнего байта массива строки
Video_Adres_Th0 = (Nstr - NomerNath) * KolBytStr + KolBytStr + Video_Adres; //адрес первого байта
//это адрес текущих 2 точек вывода - последний байт строки
while (TIM6->CNT < Ts)continue;//ждём момента для вывода 1 точки
GPIO_SetBits(PORT_OUT1_ON_OSD, OUT1_ON_OSD);//вкл. сигнала видео
Vt = (uint32_t)(*--Video_Adres_Th0) << SDWIG_RGBT; //первые две точки
while (Kt--) {
Vt1 = Vt;
Vt = Vt >> 4; //спустим старший полубайт
Ts += Td; //время следующей точки
while (TIM6->CNT < Ts)
continue; //ждём момента для вывода точки
PORT_RGBT->ODR = Vt; //вывод старшего полубайта
Ts += Td; //время следующей четной точки
Vt = (uint32_t)(*--Video_Adres_Th0) << SDWIG_RGBT; //следующий байт на разложение на точки
while (TIM6->CNT < Ts)continue; //ждём момента для вывода точки
PORT_RGBT->ODR = Vt1; //вывод младшего полубайта
}
} else { //вывод "прямо"
Поясню, что строка, где "//ждём момента для вывода 1 точки" это и есть интервал от начала прерывания до начала вывода. Вот он то и "плавает". Кстати следующая строка и есть ваше "дернуть ногой".