Попробовал сделать генерацию step сигнала для шаговых моторах используя встроенный контроллер RMT.
после нескольких попыток заставить его работать хотел было уже бросить. Проблема была, что вызов установки значений частоты приводил к блокировке функции.
после многократных попыток понять причину блокировки - бросил эту затею. На некоторых ресурсах читал, что нужно обновлять фреймфорк ардуино до версии 5.* . Но у меня это не получилось.
Но нашел техническую документацию на esp32 и там есть описание регистров rmt контроллера.
Спустя еще сутки получилось генерировать импульсы.
bool MotorStepRMT::init() {
// --- DIR ---
gpio_set_direction((gpio_num_t)_dirPin, GPIO_MODE_OUTPUT);
GPIO.out_w1tc = (1 << _dirPin); // DIR = LOW
// --- EN ---
gpio_set_direction((gpio_num_t)_enablePin, GPIO_MODE_OUTPUT);
GPIO.out_w1tc = (1 << _enablePin); // EN = LOW (мотор включён)
// --- RMT TX канал ---
rmt_config_t rmt_conf = RMT_DEFAULT_CONFIG_TX((gpio_num_t)_stepPin, _rmtChannel);
rmt_conf.clk_div = RMT_CLK_DIV;
rmt_conf.mem_block_num = 1;
rmt_config(&rmt_conf);
esp_err_t err = rmt_driver_install(_rmtChannel, 0, 256);
if (err != ESP_OK) {
xPrintf("RMT driver install FAILED ch=%d err=%d\n", _rmtChannel, err);
return false;
}
// Выключаем передачу
RMT.conf_ch[_rmtChannel].conf1.tx_conti_mode = 0;
RMT.conf_ch[_rmtChannel].conf1.tx_start = 0;
RMT.conf_ch[_rmtChannel].conf1.mem_rd_rst = 1;
RMT.conf_ch[_rmtChannel].conf1.mem_rd_rst = 0;
RMT.conf_ch[_rmtChannel].conf1.mem_owner = 0;
RMT.conf_ch[_rmtChannel].conf0.mem_size = 2;
_items[0].duration0 = 100; _items[0].level0 = 1;
_items[0].duration1 = 100; _items[0].level1 = 0;
_items[1].duration0 = 0; _items[1].level0 = 0;
_items[1].duration1 = 0; _items[1].level1 = 0;
RMTMEM.chan[_rmtChannel].data32[0].val = _items[0].val;
RMTMEM.chan[_rmtChannel].data32[1].val = _items[1].val;
RMT.conf_ch[_rmtChannel].conf0.clk_en = 1;
RMT.conf_ch[_rmtChannel].conf0.div_cnt = RMT_CLK_DIV; // делитель 256
xPrintf("RMT driver installed ch=%d OK\n", _rmtChannel);
xPrintf("RMT ch=%d step=%d\n", _rmtChannel, _stepPin);
return true;
}
// =============================================================================
// setSpeed() — частота в Гц, знак = направление
// =============================================================================
void MotorStepRMT::setSpeed(int32_t freq) {
if (freq == 0) {
stop();
return;
}
// Применяем реверс
int32_t target = freq * _conf.revers;
uint32_t freq_hz = (uint32_t)abs(target);
if (freq_hz < RMT_FREQ_MIN) freq_hz = RMT_FREQ_MIN;
// Полупериод в тиках: f_clk = 80 МГц / 256 = 312500 Гц
// half_ticks = f_clk / (2 * freq_hz)
uint32_t half_ticks = 312500 / (2 * freq_hz);
if (half_ticks < RMT_HALF_TICKS_MIN) half_ticks = RMT_HALF_TICKS_MIN;
if (half_ticks > RMT_HALF_TICKS_MAX) half_ticks = RMT_HALF_TICKS_MAX;
// Обновляем буфер
_items[0].duration0 = (uint16_t)half_ticks;
_items[0].level0 = 1;
_items[0].duration1 = (uint16_t)half_ticks;
_items[0].level1 = 0;
// DIR через регистры GPIO
int dir = (target > 0) ? 1 : 0;
if (dir != _lastDir) {
if (dir) {
GPIO.out_w1ts = (1 << _dirPin); // HIGH
} else {
GPIO.out_w1tc = (1 << _dirPin); // LOW
}
_lastDir = dir;
}
// Запись в память RMT на лету
RMTMEM.chan[_rmtChannel].data32[0].val = _items[0].val;
// Отладка
// uint32_t mem_val = RMTMEM.chan[_rmtChannel].data32[0].val;
// xPrintf("ch=%d written half_ticks=%u mem.val=0x%08X\n", _rmtChannel, half_ticks, mem_val);
// Запуск передатчика (если не был запущен)
RMT.conf_ch[_rmtChannel].conf1.tx_conti_mode = 1;
RMT.conf_ch[_rmtChannel].conf1.tx_start = 1;
_lastFreq = target;
_lastUpdate = micros();
}
// =============================================================================
// stop()
// =============================================================================
void MotorStepRMT::stop() {
if (_lastFreq != 0) {
fixPosition();
RMT.conf_ch[_rmtChannel].conf1.tx_start = 0; // остановка передатчика
_lastFreq = 0;
_lastUpdate = micros();
}
}
Глючные библиотеки получается
И еще обнаружил странную проблему.
из описания RMT имеет 8 независимых каналов 0..7
Однако на канале 0 сделать генерацию импульсов не вышло. Давал задание на генерацию 100 Гц. Но реально на пине получал более 200 кГц.
Сместил каналы на 1 для левого мотора и 2 для правого. Все заработало как положено.
И есть еще ограничение на 5Гц. Если установить 4 то генерация работает не верно и опять на выходе получаем десятки кГц. Это скорее с делителем связано.Но не стал вникать просто если меньше - установил 0. Но если нужна точность = то такой вариант конечно не подойдет. В моем же случае это не существенно. Так как 5 гц это примерно 0,5 мм/сек, что ни как не повлияет на его работу.