Аппаратный учет числа импульсов ШИМ
26.10.2016, 00:56
|
|
|
Частый гость
Регистрация: 06.10.2008
Адрес: Ростов-на-Дону
Сообщений: 49
Сказал спасибо: 5
Сказали Спасибо 4 раз(а) в 3 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
Сообщение от omercury
|
1. Какова частота STEP с Вашего "велосипеда"?
2. Какова частота ШИМ драйвера приводов ШД?
3. Сколько шагов пропустит драйвер за один период ШИМ?
|
Пока гонял на 400 мм/мин, больше не тянет.
400 * 160 шагов/мм * 16 делений / 60 сек = 17 кГц
ШИМ драйвера 30-50кГц
Если драйвер пропустит микрошаги, это не проблема, просто вместо последовательного подключения обмоток будет, например, последовательное подключение пар обмоток. Таким образом на низких частотах обеспечивается плавность, а на высоких нет пропуска шагов.
Сообщение от omercury
|
|
Ну и пожалуй самый главный вопрос: Пацаны, вы по какому принципу себе такие "говорящие" ники выбираете?
|
Что в голову пришло, то и написал.
Так вот, я же не договорил. Это в обычной памяти переключение битов не работает через пдп, а для GPIO же есть BSRR. Можно настроить таймер на каждом тике запускать пдп, который будет в цикле из буфера на 2 элемента выгребать int и писать в BSRR. Вопрос только в задержке, за сколько запустится этот самый пдп, если их будет много.
PS. кто-то уже провел такой эксперимент.
http://caxapa.ru/395890.html
Последний раз редактировалось backlan; 26.10.2016 в 01:11.
Причина: Вспомнил, что хотел сказать.
|
|
|
|
26.10.2016, 01:13
|
|
|
Почётный гражданин KAZUS.RUN
Регистрация: 25.05.2010
Адрес: г. Королёв
Сообщений: 8,487
Сказал спасибо: 30
Сказали Спасибо 3,070 раз(а) в 2,011 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
Сообщение от backlan
|
|
больше не тянет
|
Больше не тянуть вполне может и сам мотор - скорость нарастания тока в обмотках тоже не бесконечно малая. Плюс падение момента с нарастанием оборотов.
Сообщение от backlan
|
|
Вопрос только в задержке, за сколько запустится этот самый пдп, если их будет много.
|
В любом случае это будет быстрее, чем "переварит" мотор. Самая медленная часть в Вашем случае именно механика.
|
|
|
|
26.10.2016, 09:37
|
|
|
Почётный гражданин KAZUS.RUN
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,481
Сказал спасибо: 396
Сказали Спасибо 2,222 раз(а) в 1,317 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
Мне так кажется, топикстартер вообще-то идет не по правильному пути, особенно заморачиваясь с чтением счетного регистра через пдп, и особенно с заморочками с выходными портами. Читать то по пдп можно, но все равно придется все время программно сидеть в цикле ожидания, проверяя то, чего сбросил пдп. Получается, что на время работы ШД все остальные операции с МК будут перекрыты ожиданием.
И кстати, ШГ в режиме микрошага управляется двумя ступенчатыми сигналами, близкими к синусоиде, сдвинутыми на 90° относительно друг друга.
И лично мне кажется вообще чето во всей этой затее есть неправильное. Если уже есть самодельный контроллер ШД на МК, то зачем ставить еще одну коробочку с похожим функционалом? Это у ардуинистов принято наслаивать бутерброды плат на штырьках и клеммниках, плодя кучу промежуточных модулей в силу нехватки ресурсов каждого из них.
По-хорошему бы вот, главный управляющий контроллер должен лишь выдать команды исполнительным контроллерам в формате "куда и насколько и с какой скоростью переместить". А уже исполнительные контроллеры ШД, работающие через силовые драйвера ШД, должны сами посчитать импульсы.
Либо, если хотите одним МК управлять всем, то просто берите более мощный МК с большим числом таймеров. Но и тут могут быть затыки, надо сначала просмотреть связи таймеров и наличие таймеров с нужными номерами. В результате по цене такое решение окажется чуть ли не дороже, чем три раздельных МК, управляющих каждым ШД.
Последний раз редактировалось NewWriter; 26.10.2016 в 09:49.
|
|
|
|
27.10.2016, 00:37
|
|
|
Частый гость
Регистрация: 06.10.2008
Адрес: Ростов-на-Дону
Сообщений: 49
Сказал спасибо: 5
Сказали Спасибо 4 раз(а) в 3 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
Новый вариант, на счётчике байт dma.
Нажмите, чтобы открыть спойлер
|
Код:
|
#include "stm32f0xx_syscfg.h"
#include "stm32f0xx_gpio.h"
#include "stm32f0xx_rcc.h"
#include "stm32f0xx_tim.h"
#include "stm32f0xx_exti.h"
#include "stm32f0xx_adc.h"
#include "stm32f0xx_dma.h"
#include "stdbool.h"
char dummyArray[256];
//================================================== =======================
#define SYSTEM_CLOCK 48000000 //частота процессора и таймеров
#define SYSTEM_TIMER_CLOCK 6000000 //стоит кварц на 8 МГц *6 /8
//================================================== =======================
void init_pins()
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
//================================================== =======================
void connect_pins()
{
//stm32f031 datasheet, 31
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_2); //TIM1 CH1
}
//================================================== =======================
void init_tim()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef timerBase;
TIM_TimeBaseStructInit(&timerBase);
timerBase.TIM_Prescaler = 0; //длительность шага будет задаваться в процессе
timerBase.TIM_Period = 1; //скважность всегда 50%, для этого хватит 2 тактов на период
TIM_TimeBaseInit(TIM1, &timerBase);
TIM_OCInitTypeDef timerPWM;
TIM_OCStructInit(&timerPWM);
timerPWM.TIM_Pulse = 0; //регулирование скважности не нужно
timerPWM.TIM_OCMode = TIM_OCMode_Toggle;
timerPWM.TIM_OutputState = TIM_OutputState_Enable;
TIM_OC1Init(TIM1, &timerPWM);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
}
//================================================== =======================
void init_dma()
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef dmaInit;
dmaInit.DMA_BufferSize = 256;
dmaInit.DMA_DIR = DMA_DIR_PeripheralSRC;
dmaInit.DMA_M2M = DMA_M2M_Disable;
dmaInit.DMA_MemoryBaseAddr = dummyArray;
dmaInit.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dmaInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
dmaInit.DMA_Mode = DMA_Mode_Circular;
dmaInit.DMA_PeripheralBaseAddr = &TIM1-›PSC;
dmaInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dmaInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dmaInit.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel5, &dmaInit);
//TIM_DMAConfig(TIM1, TIM_DMABase_CNT, TIM_DMABurstLength_1Transfer);
TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE);
}
//================================================== =======================
void init_timer()
{
SysTick-›LOAD = SysTick_LOAD_RELOAD_Msk;
SysTick-›CTRL = SysTick_CTRL_ENABLE_Msk;//SysTick_CTRL_CLKSOURCE_Msk |
}
//================================================== =======================
void init()
{
init_pins();
connect_pins();
init_tim();
init_dma();
init_timer();
}
//================================================== =======================
inline int get_timer()
{
return -SysTick-›VAL; //он всегда downcounter, тикает в обратную сторону
}
//================================================== =======================
inline int time_delta(int value) //максимум 16777216/6000000 ~= 2 сек
{
return (get_timer() - value) & 0xFFFFFF;
}
inline int get_count()
{
DMA1_Channel5-›CNDTR;
}
//================================================== =======================
int main(void)
{
init();
int time = get_timer();
const int UPDATE_TIME = 100;
int period[] = {10, 50, 60, 200};
int index = 0;
TIM1-›PSC = period[index];
TIM_Cmd(TIM1, ENABLE);
int last = get_count(); //здесь лежит число импульсов
while (1)
{
if (time_delta(time) › UPDATE_TIME)
{
time = get_timer();
index = (index + 1) & 3;
TIM1-›PSC = period[index];
int current = get_count();
int delta = current - last;
static int cc = 0;
if (++cc › 4)
cc = 0;
last = current;
}
}
} |
Осталось выяснить, можно ли задать ему произвольный адрес, чтобы не выделять здоровый массив dummyArray лишь для того, чтобы под рукой был счетчик.
|
|
|
|
27.10.2016, 01:01
|
|
|
Почётный гражданин KAZUS.RUN
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,481
Сказал спасибо: 396
Сказали Спасибо 2,222 раз(а) в 1,317 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
 счетчик числа транзакций DMA будет выполнять ту же работу, что счетчик числа событий UEV (обновления) таймера. Только в процесс вовлекают еще и канал DMA, и уж совсем для полного счастья - массив размером до 64 килобайт - по количеству возможных транзакций DMA. И счетчик транзакций считает число оставшихся от начального значения, а не число проведенных транзакций.
Нужно убрать инкремент адресов памяти (DMA_MemoryInc), тогда будет писать в один и тот же адрес памяти. А отслеживать программно число оставшихся транзакций - это тупиковый путь.
Если задать начальное значение для счетчика DMA, то DMA после передачи последнего элемента выключится и, если разрешено, вызовет прерывание TCIF. В этом прерывании можно будет остановить таймер. Максимальное число отсчитываемых таким способом импульсов - 65536.
Сообщение от backlan
|
|
можно ли задать ему произвольный адрес
|
"ему" - это чему? Произвольный адрес массива уже и так задан - второй конец DMA-пути.
Так же можно задать любой адрес на первом конце DMA. Вообще любой.
Последний раз редактировалось NewWriter; 27.10.2016 в 01:41.
|
|
|
|
27.10.2016, 15:52
|
|
|
Частый гость
Регистрация: 06.10.2008
Адрес: Ростов-на-Дону
Сообщений: 49
Сказал спасибо: 5
Сказали Спасибо 4 раз(а) в 3 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
Сообщение от NewWriter
|
1. счетчик числа транзакций DMA будет выполнять ту же работу, что счетчик числа событий UEV (обновления) таймера.
2. Нужно убрать инкремент адресов памяти (DMA_MemoryInc), тогда будет писать в один и тот же адрес памяти.
|
1. Всё верно, для того и делалось, зато не приходится ещё один таймер занимать. Теперь мне на все 4-5 осей таймеров хватит.
2. Точно! Я думал, что напрямую счётчик оставшихся операций будет недоступен, и надо будет через указатель на память вытаскивать значения. Тогда почти всё готово. Ещё бы как-то объяснить DMA, чтобы он в память не лез
|
|
|
|
27.10.2016, 16:59
|
|
|
Почётный гражданин KAZUS.RUN
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,481
Сказал спасибо: 396
Сказали Спасибо 2,222 раз(а) в 1,317 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
1. Не спешите радоваться. Посмотрите табличку распределения запросов по каналам. Каналов всего 5 в F0чч, и может не получиться распределить все запросы.
2а. Регистр CNDTR имеет режим доступа read/write. Но не обязательно его читать. Когда он будет =0, канал остановится и отправит (если разрешено) запрос прерывания по передаче полного буфера.
2б. DMA - ... доступ к памяти. Так что полюбому второй конец маршрута будет подключен к какой-либо памяти.
|
|
|
|
27.10.2016, 17:53
|
|
|
Частый гость
Регистрация: 06.10.2008
Адрес: Ростов-на-Дону
Сообщений: 49
Сказал спасибо: 5
Сказали Спасибо 4 раз(а) в 3 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
Уже посмотрел для STM32F100 и распихал, 5 осей влезло, ещё и 4 выхода для ШИМ осталось. Думал сделать режим с длиной периода = 2 такта и заполнением 50%, но запросы TIM_DMA_Update и TIM_DMA_CC1 идут к разным каналам, так что не прокатило. Сделал toggle mode для выхода таймера, и здесь небольшая засада - минимальная длительность периода = 2 тактам, половина возможной частоты на этом теряется. А хочется сделать, чтобы на каждом срабатывании CNT выход GPIO переключался. Ну в общем и так сойдёт  .
По тактированию тоже всё сошлось, как раз из-за этого деления частоты получалось в 2 раза меньше.
Последний раз редактировалось backlan; 27.10.2016 в 18:03.
|
|
|
|
29.10.2016, 15:45
|
|
|
Частый гость
Регистрация: 06.10.2008
Адрес: Ростов-на-Дону
Сообщений: 49
Сказал спасибо: 5
Сказали Спасибо 4 раз(а) в 3 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
Для большого периода шага понадобилось вручную переключать выход таймера. Поскольку он сделан toggle, сразу не разберёшь, в каком состоянии находится выход, и хотелось бы сделать переключение так же, как он сам делает. Если CCRx = 0, тогда подходит такой код:
|
Код:
|
TIM2-›CNT = TIM2-›ARR;
TIM2-›EGR = TIM_EGR_UG; |
Если CCRx != 0, тогда такой
|
Код:
|
TIM2-›EGR = TIM_EGR_UG;
TIM2-›CNT = TIM2-›CCR1; |
Последний раз редактировалось backlan; 12.11.2016 в 17:00.
Причина: баг в коде
|
|
|
|
07.01.2017, 16:24
|
|
|
Частый гость
Регистрация: 06.10.2008
Адрес: Ростов-на-Дону
Сообщений: 49
Сказал спасибо: 5
Сказали Спасибо 4 раз(а) в 3 сообщении(ях)
|
Re: Аппаратный учет числа импульсов ШИМ
Нашел один интересный баг, с которым пришлось повозиться пол дня. Если в процессе работы таймера записать ARR = 0, то таймер зависнет, переключение бита CEN не поможет. Под отладчиком это выглядело так, как будто таймер сломался, потому что в ARR уже записалось новое значение, которое выглядело нормальным, бит CEN стоял. А если щёлкнуть UG, таймер продолжал дальше нормально работатьб потому что ARR перезаписывался на нормальный.
И ещё одно "открытие". Если не установлен бит ARPE, тогда лучше не трогать ARR, когда таймер включен, иначе он может проскочить максимальное значение. Например:
ARR = 1000, CNT = 800.
Записываем ARR = 500, а CNT продолжает считать до максимального значения 2^16. Эти грабли пару дней искал, выглядело как ошибка алгоритма коррекции траектории. После исправления стало попадать практически пиксель в пиксель.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 13:20.
|
|