|
Замечал ли кто-то странности с PWM на lpc2103 ?, непонятное поведение регистра сравнения в PWM режиме |
|
|
|
Jul 7 2008, 14:46
|
Участник

Группа: Участник
Сообщений: 21
Регистрация: 15-02-07
Из: Москва
Пользователь №: 25 386

|
Уважаемый ALL, может быть кто-то сталкивался, помогите в какую сторону копнуть... IAR 5.11, IAR Elf Linker for ARM 5.11.0.50622 (5.11.0.50622) IAR C/C++ Compiler for ARM 5.11.0.20622 (5.11.0.20622) Вывожу с помощью PWM синус по 800 точкам. таблица синуса объявлена полуволной!!! из констант unsigned int const sin1024[400]={\ ... }; константы в сегменте флэш-памяти lpc2103. Задача вывода PWM тривиальная - по прерыванию 3-го канала (период) обновляю данные регистра сравнения T0MR0. после RC цепочки на ноге МАТ0.0 смотрим синус осциллографом. Имею абсолютно непонятную ситуацию - "задир" (то есть T0MR0 имеет сильно неверное значение) (иногда два "задира", а иногда - ни одного) на синусе, причем этот задир только на одной (левой "верхней" то бишь значенияT0MR0 должны лежать в диапазоне [0 .. 1/2Period ] ) полуволне, и самое поразительное, что в зависимости от положения звёзд на рабочем проекте "задир(ы)" то проявляются, то не проявляется. На тестовом проекте задир всегда постоянен и всегда один. Таблица синуса правильная, в пошаговом режиме проблем не возникает, на кристалле в головном проекте крутится ещё несколько прерываний, они не являются причиной (иногда синус абсолютно чистый, а иногда именно в данном месте то один, то два "задира"). Проблема проявляется даже на прилагаемом тестовом проекте (должен заработать у каждого под иар5.11 ). кварц 12мГц, обычная отладка от Олимекса с 2103. Прошу оказать конструктивную помощь, высказать замечание или кинуть в меня соответствующей ссылкой. Умозрительные предположения прошу делать аккуратно, ибо пока все умозрительные предположения стукнулись головой о реальный камень... ПРИЛАГАЕМЫЙ ПРОЕКТ
test_pwm_issue_lpc2103.rar ( 89.07 килобайт )
Кол-во скачиваний: 114
Сообщение отредактировал avva - Jul 7 2008, 14:54
--------------------
С уважением,
|
|
|
|
|
Jul 8 2008, 04:08
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
Както странно, у Вас PWM_period_val и период таймера (задающий частоту ШИМ) и амплитуда синуса.... Вот тут: Код if (i>399){ // it seems problem in this part of val=( (PWM_period_val-( (PWM_period_val*usin[i-400] -1 )>>10))>>1 ); }else{ val=( ((PWM_period_val+((PWM_period_val*usin[i] -1 )>>10))>>1)); } зачем "-1" ? Искажений добавляете? Впрочем возможно что в вашем случае они не появятся (при перермножении 375 на табличные значения наверняка не будет произведения где младшие 10 бит нулевые). Может хотели ((PWM_period_val-1)*usin[i]) ? Да и вообще весь этот код упростить можно. И почему у Вас в таблице полуволны синуса первый элемент 3 а не 0? А если заменить на 0 то как раз та самая "-1" то и вылезет.  Вот эта конструкция Код i = (i != 799) ? ++i : 0; тоже достойна похвалы...
|
|
|
|
|
Jul 8 2008, 07:08
|
Участник

Группа: Участник
Сообщений: 21
Регистрация: 15-02-07
Из: Москва
Пользователь №: 25 386

|
Цитата Както странно, у Вас PWM_period_val и период таймера (задающий частоту ШИМ) и амплитуда синуса.... ... зачем "-1" ? Искажений добавляете? Впрочем возможно что в вашем случае они не появятся (при перермножении 375 на табличные значения наверняка не будет произведения где младшие 10 бит нулевые). Может хотели ((PWM_period_val-1)*usin[i]) ? Да и вообще весь этот код упростить можно. Alex03, проблема абсолютно в другом.... (я согласен с вами, что "-1" это лишнее, но это всё-равно. таблица полу-синуса хоть с 10 может начинаться - она на 0х3FF отнормирована, так что там всё-равно.). проблема в том, что каким-то непонятным образом в tmrmr0 !однократно! попадает!? значение больше или равное периоду pwm, что вызывает установку соответсвтующей ноги в 0 на период шима. как такое происходит - ума не приложу. пока все догадки и эксперименты были из области фантастики, по-этому я решил обратиться к многоуважаемому сообществу. Цитата И почему у Вас в таблице полуволны синуса первый элемент 3 а не 0? А если заменить на 0 то как раз та самая "-1" то и вылезет.  Вот эта конструкция Код i = (i != 799) ? ++i : 0; тоже достойна похвалы...  это стандартная конструкция языка ANSI C, думаю это вопрос не принципиальный ) Цитата(GetSmart @ Jul 7 2008, 19:41)  Могу сказать, что делал почти точно так же на LPC2132 и всё работало чудесно. Только перезагрузку MACH регистра делал по прерыванию 0-ого канала, который задаёт период PWM, то бишь обнуляет счётчик. В возникающем при этом прерывании обновлял PWMMR1 и стробировал PWMLER, а затем сразу же выходил из прерывания.
Кстати, таймер отличается от PWM тем, что у него нет защёлок на MACH регистрах (регистра PWMLER). Может в этом косяк. я использую именно описанный в доке режим PWM, канал 3 - задаёт период PWM, а каналы 0 1 и 2 в рабочем проекте - разные PWM с одним периодом (канал 3) собственно в данном случае проблему надо глазами видеть. Понимаете, я бы понял, если бы проблема проявлялась на "пике" какого-то канала, тогда можно было бы говорить о переполнении и всякой такой простой ерунде, однако "задир" проявляется - фото (качество не очень, синус - идеальный но имеет "задир") Буду благодарен за умную мысль по теме. ФОТО "ЗАДИРА"
 Р Взображение СѓРСеньшено
(53.27 килобайт)
|
--------------------
С уважением,
|
|
|
|
|
Jul 8 2008, 09:16
|
Участник

Группа: Участник
Сообщений: 21
Регистрация: 15-02-07
Из: Москва
Пользователь №: 25 386

|
Уважаемый GetSmart, похоже, что вы оказались правы или где-то очень очень рядом около того.
СПАСИБО.
Во всяком случае, патч вот этих строчек в тестовом проекте привёл к желаемому результату, жаль только, что форма синуса изза остановки таймера периода в момент прерывания и перезагрузки регистров сравнения, немножечко будет искажена. думаю, искажением формы можно пренебречь
100+ T0TCR = 0x01; //перезапуск таймера после окончания прерывания таймера
218 T0MCR = 0x0E00; // добавление STOP в процедуре инита периода шима таймера0 канал3
--------------------
С уважением,
|
|
|
|
|
Jul 8 2008, 09:22
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
Цитата(avva @ Jul 8 2008, 13:08)  Код i = (i != 799) ? ++i : 0; это стандартная конструкция языка ANSI C, думаю это вопрос не принципиальный ) ИМХО это из области Код i += i++ + ++i; Не рекомендовал бы так писать. К тому же если объявить i как volatile то переменная будет прописываться в памяти дважды (да и в некоторых других случаях, как то debug, тоже), хоть и одним значением. Лучше/правильнее Код i = (i != 799) ? i+1 : 0; или уж Код if(i != 799) ++i; else i = 0; Впрочем, ДА, к теме топика не имеет отношения. Цитата(avva @ Jul 8 2008, 13:08)  Понимаете, я бы понял, если бы проблема проявлялась на "пике" какого-то канала, тогда можно было бы говорить о переполнении и всякой такой простой ерунде, однако "задир" проявляется - фото RC-цепочка двигает фазу, так что возможно что на фото и есть пик синусоиды...
|
|
|
|
|
Jul 8 2008, 09:24
|
Участник

Группа: Участник
Сообщений: 21
Регистрация: 15-02-07
Из: Москва
Пользователь №: 25 386

|
Alex03, спасибо, я учту в будущем. (серьёзно). Цитата RC-цепочка двигает фазу, так что возможно что на фото и есть пик синусоиды... Фигню полную написали вы сейчас насчёт возможного пика.
Сообщение отредактировал avva - Jul 8 2008, 09:27
--------------------
С уважением,
|
|
|
|
|
Jul 8 2008, 10:01
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
Цитата(avva @ Jul 8 2008, 15:24)  Alex03, спасибо, я учту в будущем. (серьёзно). Так и я серьёзно, стоит ++ переставить и уже всё интересней  Код int i = 10; i = (i != 799) ? i++ : 0; MSVC 2003 - результат 10! Цитата Фигню полную написали вы сейчас насчёт возможного пика. Я не знаю Ваших частот и номиналов, но чем больше R и С тем больше сдвиг фазы стремится к 90 градусов (с сильным уменьшением амплитуды). И тем правильнее форма сигнала. Хотя судя по тому что "задир" такой "резкий" номиналы у Вас довольно небольшие. Цитата(GetSmart @ Jul 8 2008, 15:36)  ... Только для обхода этого косяка не обязательно останавливать таймер. Достаточно уменьшить амплитуду синусоиды на несколько процентов чтобы в регистр MR не записывались очень маленькие значения. Например в диапазоне от 25 до 375. Минимально допустимое значение для MR зависит от скорости реакции на прерывание. Если у этого прерывания будет не самый высокий приоритет или будут возникать другие прерывания недопускающие вложенность, то будут глюки. +1 А скорость реакции увеличить легко выкинув полонстью Код __irq __arm void irq_handler (void) { void (*interrupt_function)(); unsigned int vector;
vector = VICVectAddr; // Get interrupt vector. interrupt_function = (void(*)())vector; if(interrupt_function != NULL){ interrupt_function(); // Call vectored interrupt function. } VICVectAddr = 0; // Clear interrupt in VIC. return; } Достаточно Код ldr pc, [pc, #-0xFF0] в области векторов прерываний (по адресу 0x00000018) И timer0_handler() объявить с __irq и с VICVectAddr = 0; в конце. Зачем проверки, Вы сами себе не доверяете? Ну и задержать можно всё на период Код __irq __arm void timer0_handler(void) { static unsigned int i; static unsigned int val = ХХХ;
T0MR0 = val;
// Вычисление val для след. прерывания.
VICVectAddr = 0; // Clear interrupt in VIC. }
|
|
|
|
|
Jul 8 2008, 10:26
|

Частый гость
 
Группа: Свой
Сообщений: 135
Регистрация: 6-04-07
Из: Бронницы
Пользователь №: 26 809

|
Цитата(avva @ Jul 8 2008, 13:16)  100+ T0TCR = 0x01; //перезапуск таймера после окончания прерывания таймера причина засора прояснилась, однако я совершенно не согласен что можно принебрегать формой синусоиды , вводя такие погрешности уважаемый АВВА вы из чистой синусоиды на спектре получите фиг знает что. Вопрос - почему нельзя перегружать значение по соответствующему прерыванию (для нулевого канала по прерыванию матча нулевого канала )- будет все хорошо и вперед и назад ?
--------------------
если еррата пуста - это не хорошо а плохо
|
|
|
|
|
Jul 8 2008, 10:34
|
Участник

Группа: Участник
Сообщений: 21
Регистрация: 15-02-07
Из: Москва
Пользователь №: 25 386

|
Цитата(GetSmart @ Jul 8 2008, 13:36)  Я оказался прав на 100%  Только для обхода этого косяка не обязательно останавливать таймер. Достаточно уменьшить амплитуду синусоиды на несколько процентов чтобы в регистр MR не записывались очень маленькие значения. Например в диапазоне от 25 до 375. Минимально допустимое значение для MR зависит от скорости реакции на прерывание. Если у этого прерывания будет не самый высокий приоритет или будут возникать другие прерывания недопускающие вложенность, то будут глюки. Ок, GetSmart, Вы оказались правы на 100%  . К сожалению в данном случае мне нужен весь диапазон значений PWM и не удастся ввести постоянную корректировочную составляющую. Данный проект синуса - это просто тестовый проект который был собран лишь для нахождения глюка. Насчёт вложенных прерываний - да, придётся сделать вложенность по всей видимости. Alex03, насчёт RC замнём - фильтруется несущая 40кГц для синуса 50Гц; насчёт ++ тоже в курсе У меня в нормальном проекте всего пока 5 прерываний крутится I2C, ADC, 2 периода ПВМ, один из которого системный синхронизующий и второй - достаточно медленный и ещё один таймера сравнения. В целом идей Ваш понятен и принят, насчёт проверок для дебилов - знаете, иногда когда "jmp $" не помогает, очень полезным оказывается писать все проверки и иногда вставлять даже в код NOP  .
--------------------
С уважением,
|
|
|
|
|
Jul 8 2008, 10:56
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(cebotor @ Jul 8 2008, 16:26)  Вопрос - почему нельзя перегружать значение по соответствующему прерыванию (для нулевого канала по прерыванию матча нулевого канала )- будет все хорошо и вперед и назад ?  Вот это хорошая идея. Если при срабатывании MATCH-а вызывать прерывание, то можно сразу же перезагружать этот MR регистр. Этот алгоритм подходит когда в сигнале нет резких скачков, как раз для синусоиды. Однако нельзя будет загружать в MR значение большее или равное периоду. Таким образом за один период для трёхканального ШИМа будет три раза срабатывать одно и то же прерывание, в котором анализируя флаг TxIR можно узнать какой MR сработал. Цитата(avva) К сожалению в данном случае мне нужен весь диапазон значений PWM и не удастся ввести постоянную корректировочную составляющую. Остановив таймер Вы её уже ввели  То есть после обнуления таймера появляются те же ~20 тактов паузы, только они теперь увеличили период с 375 до грубо 395 тактов PCLK. При этом получился плавающий период и нестабильная частота, особенно в присутствии других прерываний.
Сообщение отредактировал GetSmart - Jul 8 2008, 11:04
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jul 8 2008, 11:13
|

Частый гость
 
Группа: Свой
Сообщений: 135
Регистрация: 6-04-07
Из: Бронницы
Пользователь №: 26 809

|
Цитата(GetSmart @ Jul 8 2008, 14:56)  Однако нельзя будет загружать в MR значение большее или равное периоду. Cмысл этой фразы для меня остался тайной , по моему и так нельзя загружать в MR значение большее периода Цитата(GetSmart @ Jul 8 2008, 14:56)  Таким образом за один период для трёхканального ШИМа будет три раза срабатывать одно и то же прерывание, в котором анализируя флаг TxIR можно узнать какой MR сработал. я честно признаться не помню как в ЛПЦ работает ВИК , так что приходиться ли делить прерывание внутри или снаружи - это зависит от конкретного камня , а вот сама проблема , причину которой вы так удачно предположили - касается практически всех кристаллов в которых нету спец регистров типа прелоад значения
--------------------
если еррата пуста - это не хорошо а плохо
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|