Почти L297 на Почти Verilog -e

А заменить на ПЛИС которая у меня валяется без дела. Да и не только, также экономия играет свою роль, вместо покупки 3 драйверов установить одну ПЛИС при почти той же стоимости.
L297 устроенна довольно хитрым образом, и образ этот описан в даташите http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00000063.pdf
Но самое главное в даташите — это граф переходов. Выглядит он вот так:

Фактически с помощью графов можно построить совершенно любую схему на любой алгоритм. К моему удивлению все остальное в даташите не так интересно. Все что надо сделать построить этот граф на verilog.
Возможно конечно мой метод постройки такого автомата не идеален. (А я это знаю, еще со времен ПТЦА), Но тем не менее он работает.
При полном проходе по графу шаговый двигатель будет работать в режиме HALF-MODE (полушага) Кроме этого режима в L297 есть еще два. NORMAL MODE и Wave Mode. Последний я не описывал. Но я думаю, это небольшая потеря. Переключаются они с помощью вывода Half/Full
Код на Verilog для Half-Mode выглядит так:
module half_step_drv(dir,clk,a,na,b,nb,ena);
input dir;
input ena;
input clk;
output a,na,b,nb;
reg a,b,na,nb;
reg[0:3] step;
always@(posedge clk)
begin
if(ena)
begin
case(step)
0 :
begin
a<=1'b0;
na<=1'b1;
b<=1'b0;
nb<=1'b1;
if(dir==1'b0)
step=step+1'b1;
else
step=3'd7;
end
1 :
begin
a<=1'b0;
na<=1'b0;
b<=1'b0;
nb<=1'b1;
if(dir==1'b0)
step=step+1'b1;
else
step=step-1'b1;
end
2 :
begin
a<=1'b1;
na<=1'b0;
b<=1'b0;
nb<=1'b1;
if(dir==1'b0)
step=step+1'b1;
else
step=step-1'b1;
end
3 :
begin
a<=1'b1;
na<=1'b0;
b<=1'b0;
nb<=1'b0;
if(dir==1'b0)
step=step+1'b1;
else
step=step-1'b1;
end
4 :
begin
a<=1'b1;
na<=1'b0;
b<=1'b1;
nb<=1'b0;
if(dir==1'b0)
step=step+1'b1;
else
step=step-1'b1;
end
5 :
begin
a<=1'b0;
na<=1'b0;
b<=1'b1;
nb<=1'b0;
if(dir==1'b0)
step=step+1'b1;
else
step=step-1'b1;
end
6 :
begin
a<=1'b0;
na<=1'b1;
b<=1'b1;
nb<=1'b0;
if(dir==1'b0)
step=step+1'b1;
else
step=step-1'b1;
end
7 :
begin
a<=1'b0;
na<=1'b1;
b<=1'b0;
nb<=1'b0;
if(dir==1'b0)
step=3'b0;
else
step=step-1'b1;
end
default :
begin
a<=1'b0;
na<=1'b1;
b<=1'b0;
nb<=1'b1;
end
endcase
end
else
begin
a<=1'bz;
na<=1'bz;
b<=1'bz;
nb<=1'bz;
end
end
endmodule
Где: Ena — Включение модуля, иначе на выходе Z состояние
CLK — Шаг двигателя
Dir — Направление
Работает это дело весьма просто. В середине есть счетчик команд step, с шагом которого выполняется определенная команда вершины графа, а именно выдача на выход определенного числа/состояния.
Normal Mode работает немного иначе. Фактически в нем пропущены все четные вершины графа.
ака вот так:

Из-за чего двигатель работает быстрее но и точность его от этого только страдает.
Вот более интересный код, созданный на основе Block Schem, Он качественно отличается от моего (благо оптимизатор работает) и над этим стоило бы когда нибудь задуматься.
Генерируется такой код почти также как и Block module через меню File -> Create/Update -> Create HDL Design File
module stepper_drv(
DIR,
CLK,
ENA,
A,
NA,
B,
NB
);
input DIR;
input CLK;
input ENA;
output A;
output NA;
output B;
output NB;
reg SYNTHESIZED_WIRE_5;
reg SYNTHESIZED_WIRE_6;
wire SYNTHESIZED_WIRE_0;
wire SYNTHESIZED_WIRE_1;
wire SYNTHESIZED_WIRE_2;
wire SYNTHESIZED_WIRE_7;
assign A = ENA ? SYNTHESIZED_WIRE_5:1'bz ;
assign B = ENA ? SYNTHESIZED_WIRE_6:1'bz ;
assign SYNTHESIZED_WIRE_2 = ~DIR;
assign SYNTHESIZED_WIRE_7 = SYNTHESIZED_WIRE_5 ^ SYNTHESIZED_WIRE_6;
always@(posedge CLK)
begin
if (ENA)
begin
SYNTHESIZED_WIRE_5 = SYNTHESIZED_WIRE_5 ^ SYNTHESIZED_WIRE_0;
end
end
always@(posedge CLK)
begin
if (ENA)
begin
SYNTHESIZED_WIRE_6 = SYNTHESIZED_WIRE_6 ^ SYNTHESIZED_WIRE_1;
end
end
assign SYNTHESIZED_WIRE_0 = SYNTHESIZED_WIRE_2 ^ SYNTHESIZED_WIRE_7;
assign SYNTHESIZED_WIRE_1 = DIR ^ SYNTHESIZED_WIRE_7;
assign NA = ENA ? ~SYNTHESIZED_WIRE_5:1'bz ;
assign NB = ENA ? ~SYNTHESIZED_WIRE_6:1'bz ;
endmodule
Данный модуль скомпилирован из вот этой схемы:

Кстати очень годная информация по шаговым двигателям описана здесь
http://en.wikibooks.org/wiki/Practical_Electronics/Stepper_Motors
Откуда и была взята эта схема
Собирая весь проект до кучи получается следующие:

Один такой блок занимает 15 макроячеек, так что с помощью epm3064 можно с легкостью заменить 4-е L297, если конечно учесть что не надо разные функции типа синхронизации итд.
Код кроме как на симуляторе еще нигде не тестировался, да и немного не то время для тестов. 4:34 утра.
Если будет интересно, то как протестирую выложу видео работы.
В конце прилаживаю проект Quartus 9.1
Это моя первая запись в сообществе так что любой «удар палкой в лоб» приветствуется.
- +4
- 05 ноября 2011, 04:57
- letni
- 1
Файлы в топике:
CNC_Scanner.zip
А прикольно. Надо добавить еще сьем напряжения с шунта, для определения предельного тока и будет полный аналог. CNC шники будут рады.
Напругу, наверняка можно снять с помощью псевдо АЦП на копеечно компараторе.
Напругу, наверняка можно снять с помощью псевдо АЦП на копеечно компараторе.
Да не будет полный аналог. Нужно еще добавить ШИМ на отдельные выводы или на выводы моторов (по выбору) и установку режима ограничения тока, вот тогда будет похоже)))
А вообще, если городить свой велосипед, то лучше уже добавить и режим удержания, который включается через пару секунд простоя, вот тогда народ оценит)
А вообще, если городить свой велосипед, то лучше уже добавить и режим удержания, который включается через пару секунд простоя, вот тогда народ оценит)
- mr_freeman
- 05 ноября 2011, 12:43
- ↑
- ↓
Я думаю это не такая большая проблема, дело лишь в том что компараторы я в плисину ну не как не засуну, а вот сделать еще один вывод ENA на каждый такой модуль это идея.
Там то и ШИМ от внешнего сигнала прикрутить можно и…
Там то и ШИМ от внешнего сигнала прикрутить можно и…
По поводу ШИМа и ENAбля.
В данной версии оно работать будет не особо.
Лучше вытащить из always блока логику ena или вообще в топ-левеле сделать. Об этом я ниже говорил.
В данной версии оно работать будет не особо.
Лучше вытащить из always блока логику ena или вообще в топ-левеле сделать. Об этом я ниже говорил.
- PPetrovich
- 06 ноября 2011, 00:20
- ↑
- ↓
В целом идея не плоха, но профессиональные CNС на таких МС (L297) не строят.
Слишком все урезано получается, не хватает многих плюшек.
До этого такие драйвера строил на 88 Меге. Хватало с трудом, сейчас требования подросли, и уже все — переход на АРМ.
Слишком все урезано получается, не хватает многих плюшек.
До этого такие драйвера строил на 88 Меге. Хватало с трудом, сейчас требования подросли, и уже все — переход на АРМ.
Второй вариант явно предпочтительнее )))
А насчет первого… Ну там можно получше сделать.
Например, смена состояний автомата. Там в каждом кейсе есть
Вынести наружу.
Еще смущает step=step+1'b1. Я сам еще учусь, но мне кажется, лучше будет, если написать вместо step+1'b1 номер того состояния, куда переходим. То есть, если из первого в второе, то step = 2. Надо проверить, да глянуть в RTL Viewer-e.
Алсо, конструкция
легко меняется на
{a,na,b,nb} <= 4'bzzzz;
В верилоге {} — шина, и её можно собрать из чего угодно. Полезная фишка,
А насчет первого… Ну там можно получше сделать.
Например, смена состояний автомата. Там в каждом кейсе есть
if(dir==1'b0)
step=step+1'b1;
else
step=step-1'b1;
Вынести наружу.
Еще смущает step=step+1'b1. Я сам еще учусь, но мне кажется, лучше будет, если написать вместо step+1'b1 номер того состояния, куда переходим. То есть, если из первого в второе, то step = 2. Надо проверить, да глянуть в RTL Viewer-e.
Алсо, конструкция
begin
a<=1'bz;
na<=1'bz;
b<=1'bz;
nb<=1'bz;
end
легко меняется на
{a,na,b,nb} <= 4'bzzzz;
В верилоге {} — шина, и её можно собрать из чего угодно. Полезная фишка,
- PPetrovich
- 05 ноября 2011, 10:19
- ↓
Согласен, в таком виде в котором она есть, она не полностью отвечает абстрактному цифровому автомату.
Не знаю надо попробовать, в любом случае, если прорисовывать в голове схему из кода, то выходит следующее.
Верхний, мой вариант.
Нижний твой. фактически меняется счетчик на регистр, думаю разница не большая
А по поводу шин, да!, незнал :)
Не знаю надо попробовать, в любом случае, если прорисовывать в голове схему из кода, то выходит следующее.
Верхний, мой вариант.
Нижний твой. фактически меняется счетчик на регистр, думаю разница не большая
А по поводу шин, да!, незнал :)
Упс, провтыкал схему.
http://imageshack.us/photo/my-images/7/l297aut.png/
http://imageshack.us/photo/my-images/7/l297aut.png/
Я переделал чуть твой код по-своему, а именно "… если из первого в второе, то step = 2… " и так далее. По макроячейкам ситуация не поменялась, но теперь умный квартус увидел тут конечный автомат. Теперь, если в RTL Viewer-e посмотреть, во что синтезируется данное кодище, то там можно увидеть FSM, к выходам которой подключена логика. Ща еще пару мыслей по улучшению попробую реализовать.
А вообще, советую почаще смотреть RTL-Viewer. Открывает глаза на многие вещи
А вообще, советую почаще смотреть RTL-Viewer. Открывает глаза на многие вещи
- PPetrovich
- 05 ноября 2011, 14:23
- ↑
- ↓
Так, я еще улучшил кодище и теперь из твоей исходной схемы получилась такая няшка:
dl.dropbox.com/u/25100873/Image%202.png
Золотистая штука — это твой конечный автомат. Дважды щелкнешь — увидишь граф переходов и всё такое.
Как видно, его выходы через OR заведены на защелки. По каждому клоку они фиксируют новое значение.
И ушли ненужные защелки.
Вот новый исходник:
dl.dropbox.com/u/25100873/half_step_drv.v
Вкратце о том, что я делал.
1) Есть такое правило(не буду объяснять, почему, просто знай, что так надо): в одном always-блоке нельзя одновременно использовать блокирующие и неблокирующие присвоения(<= и =). Исправил везде на <=
2) Явно указал, из какого состояния куда переходить, и в итоге квартус увидел конечный автомат
3) выкинул нафиг из always блока логику ena.
и вот что сделал:
assign {a,na,b,nb} = (ena)? {a_r,na_r,b_r,nb_r}: 4'bzzzz;
Что делает конструкция вида assign a = (b)? c: d;
Если то, что в скобках, истинно, то это эквивалентно assign a = с иначе будет assign a = d;
a, na, b, nb — выходные проводники, которые при ena = 1 будут непрерывно выводить состояния внутренних защелок a_r, an_r и т.д., а при ena = 0 будут в High-Z.
А если бы это было бы в always блоке, то добавились бы еще защелки(одна, скорее всего), которые бы фиксировали состояние ena в момент фронта clk.
dl.dropbox.com/u/25100873/Image%202.png
Золотистая штука — это твой конечный автомат. Дважды щелкнешь — увидишь граф переходов и всё такое.
Как видно, его выходы через OR заведены на защелки. По каждому клоку они фиксируют новое значение.
И ушли ненужные защелки.
Вот новый исходник:
dl.dropbox.com/u/25100873/half_step_drv.v
Вкратце о том, что я делал.
1) Есть такое правило(не буду объяснять, почему, просто знай, что так надо): в одном always-блоке нельзя одновременно использовать блокирующие и неблокирующие присвоения(<= и =). Исправил везде на <=
2) Явно указал, из какого состояния куда переходить, и в итоге квартус увидел конечный автомат
3) выкинул нафиг из always блока логику ena.
и вот что сделал:
assign {a,na,b,nb} = (ena)? {a_r,na_r,b_r,nb_r}: 4'bzzzz;
Что делает конструкция вида assign a = (b)? c: d;
Если то, что в скобках, истинно, то это эквивалентно assign a = с иначе будет assign a = d;
a, na, b, nb — выходные проводники, которые при ena = 1 будут непрерывно выводить состояния внутренних защелок a_r, an_r и т.д., а при ena = 0 будут в High-Z.
А если бы это было бы в always блоке, то добавились бы еще защелки(одна, скорее всего), которые бы фиксировали состояние ena в момент фронта clk.
- PPetrovich
- 05 ноября 2011, 14:52
- ↑
- ↓
И таки можно уменьшить step. У тебя он объявлен как reg [3:0] step, хотя по факту reg [2:0] step
- PPetrovich
- 05 ноября 2011, 15:07
- ↑
- ↓
гы, только что заметил, что у тебя вообще reg [0:3] step.
Это не порядок.
Вообще, в скобках [MSB:LSB], то есть от старшего бита к младшему. И если у тебя будет, например, reg [0:7] counter, то старший бит счетчика у тебя будет с индексом 0, а младший — с индексом 7. Согласись, что некрасиво и нелогично )))
Гы-гы, больше придраться не к чему.
Ах да, tri-state буфера внутри модулей делать не стоит. Только в top-levele! То есть берешь, убираешь из модуля half-step логику enable, и просто между, например, выходом a модуля half-step и пином A0 ставишь примитив TRI, а уже на него заводишь ena.
Тогда и у квартуса к тебе претензий не будет(0 warnings), и все будет сделано по всем канонам ))
Это не порядок.
Вообще, в скобках [MSB:LSB], то есть от старшего бита к младшему. И если у тебя будет, например, reg [0:7] counter, то старший бит счетчика у тебя будет с индексом 0, а младший — с индексом 7. Согласись, что некрасиво и нелогично )))
Гы-гы, больше придраться не к чему.
Ах да, tri-state буфера внутри модулей делать не стоит. Только в top-levele! То есть берешь, убираешь из модуля half-step логику enable, и просто между, например, выходом a модуля half-step и пином A0 ставишь примитив TRI, а уже на него заводишь ena.
Тогда и у квартуса к тебе претензий не будет(0 warnings), и все будет сделано по всем канонам ))
- PPetrovich
- 05 ноября 2011, 15:29
- ↑
- ↓
Вау! действительно стоящие дело сделал :)
Вот только я не понимаю сути Reg[0:3] -> Reg[3:0]. В общем-то разница с какой стороны ты начинаешь есть шоколадное печенька не велико. Важно лишь то что бы оно всегда было с одной стороны.
Другое дело так и начинаются срачи между Big-Endian и Little-Endian.
А по поводу всего остального, таки резонные замечания, спасибо!
Вот только я не понимаю сути Reg[0:3] -> Reg[3:0]. В общем-то разница с какой стороны ты начинаешь есть шоколадное печенька не велико. Важно лишь то что бы оно всегда было с одной стороны.
Другое дело так и начинаются срачи между Big-Endian и Little-Endian.
А по поводу всего остального, таки резонные замечания, спасибо!
По мне — в данном вопросе([3:0]) порядок должен быть во всем. У старшего бита старший индекс.
>>> Важно лишь то что бы оно всегда было с одной стороны.
Просто я еще ни в одном исходнике не видел такой нумерации. Принято писать [3:0] — и все это соблюдают.
Исключения — когда надо там перевернуть задом наперед что-нить. Но это уже не в объявлении reg, а в обращении к ним
>>> Важно лишь то что бы оно всегда было с одной стороны.
Просто я еще ни в одном исходнике не видел такой нумерации. Принято писать [3:0] — и все это соблюдают.
Исключения — когда надо там перевернуть задом наперед что-нить. Но это уже не в объявлении reg, а в обращении к ним
- PPetrovich
- 06 ноября 2011, 15:41
- ↑
- ↓
То бишь… Ну привыкнешь ты писать [0:n].
Это будет проблемой для того, кто будет твой исходник юзать(ну если ты поделишься ;)).
Ну и обратная ситуация — взял где-нить какую-нить корку, а там оппа — [n:0].
Это будет проблемой для того, кто будет твой исходник юзать(ну если ты поделишься ;)).
Ну и обратная ситуация — взял где-нить какую-нить корку, а там оппа — [n:0].
- PPetrovich
- 06 ноября 2011, 15:43
- ↑
- ↓
Комментарии (20)
RSS свернуть / развернуть