I'm trying to get the UART communication between my TMC2226 and my ESP32 working so that I can implement Stealthchop and Stallguard in my system. Before I start trying to do too much coding, I want to make sure the hardware is wired sufficiently, so I know it can work. Here are the connections on the current PCB (I have one ESP32 and two TMC2226's):
The following pins on the TMC2226 are connected to their own GPIO pins on the ESP32
- ENN
- DIR
- STEP
- DIAG
- INDEX
Now here's where things get weird, the RX pin (on the esp32) is connected to the PDN_UART pin on both TMC 2226 drivers. And the TX pin (on the esp32) is connected to the RX pin through a 1kOhm resistor.
This seems to correlate with this image from the TMC2226 datasheet:
I'm only concerned that this may be problematic because there's a comment in the pin definitions code that says:
#define Z_MOTOR_DIAG_PIN GPIO_NUM_39 // Don't use this as the X and Z diag pins are tied together.
Now, this doesn't make sense because the DIAG pins are not tied together, but maybe they were referring to the pdn_uart pins which are tied together.
Right now, the code is failing to get a UART connection between the chip and drivers, returning the message:
Thu Jan 1 00:00:07 1970 - This UART controller (1) is all ready installed
uart status = -1
I (7399) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
E (7409) uart: uart_write_bytes(1281): uart_num error
E (7419) uart: uart_wait_tx_done(1151): uart_num error
Thu Jan 1 00:00:07 1970 - Wrote -1 bytes with wait status -1
[0]0x55 [1]0x0 [2]0x80 [3]0x0 [4]0x0 [5]0x1 [6]0x41 [7]0x2b
E (17449) uart: uart_write_bytes(1281): uart_num error
E (17449) uart: uart_wait_tx_done(1151): uart_num error
Here is the code that initializes the tmc2226:
Motor_Driver.h
#define TCM2226_ENABLE_PIN GPIO_NUM_25
class TMC2226
{
public:
CoreLib::GpioOutput& GetEnableOutput() {
return enable_output;
}
void SetEnableOutputState(bool state) {
if (state)
enable_output.on();
else
enable_output.off();
}
public:
void writeRegister(uint8_t address, uint32_t value);
/**
* Creates a TMC 2226 motor driver
* Default Constructor, uses the following options.
*
* UART_NUM_1 as serial interface \n
* @param tmc_rx_pin The pin to be used for receiving data from TMC2226
* @param tmc_tx_pin The pin to be used for transmitting data to TMC2226
* @param tmc_enable_pin The pin to be used for enabling/disabling the TMC2226
* @param tmc_dev_addr The device address to be used when communicating with the TMC2226
* @see TMC2226(int uart_num, int rx_pin, int tx_pin)
*/
TMC2226(int tmc_tx_pin, int tmc_rx_pin, gpio_num_t tmc_enable_pin, uint8_t tmc_dev_addr, CoreLib::Logger *tmc_logger);
/**
* Creates a TMC 2226 motor driver
* @brief Constructor with level.
* @param tmc_uart_num the UART to use for communications with the TMC2226
* @param tmc_rx_pin The pin to be used for receiving data from TMC2226
* @param tmc_tx_pin The pin to be used for transmitting data to TMC2226
* @param tmc_enable_pin The pin to be used for enabling/disabling the TMC2226
* @param tmc_dev_addr The device address to be used when communicating with the TMC2226
*
*/
TMC2226(uart_port_t tmc_uart_num, int tmc_tx_pin, int tmc_rx_pin, gpio_num_t tmc_enable_pin, uint8_t tmc_dev_addr, CoreLib::Logger *tmc_logger);
int SendDatagram(uint8_t reg_addr, uint32_t value);
int SendDatagram(TMC2226_DATAGRAM &send_datagram);
int SendReqDatagram(uint8_t reg_addr);
int SendRegDatagram(TMC2226_DATAGRAM &req_datagram);
int ReceiveDataGram(TMC2226_DATAGRAM &recv_datagram);
TMC2226_DATAGRAM GetVersion(void);
/**
* @brief Set logger
* @param logger_ptr A function pointer to the logger for this state machine
*/
void SetErrorLogger(CoreLib::Logger *logger_ptr) { logger = logger_ptr; }
private:
CoreLib::UART *tmc_uart;
CoreLib::GpioOutput enable_output;
uart_port_t uart_num;
int rx_pin;
int tx_pin;
gpio_num_t enable_pin;
uint8_t dev_addr;
void Init(void);
_tmc2226_datagram rx_datagram;
_tmc2226_datagram tx_datagram;
void BuildDatagram(uint8_t addr, uint32_t value, uint8_t crc);
CoreLib::Error *error = { nullptr };
CoreLib::Logger *logger = { nullptr };
};
Motor_Driver.cpp
TMC2226::TMC2226(int tmc_tx_pin, int tmc_rx_pin, gpio_num_t tmc_enable_pin, uint8_t tmc_dev_addr, Logger *tmc_logger) {
uart_num = UART_NUM_1;
rx_pin = tmc_rx_pin;
tx_pin = tmc_tx_pin;
enable_pin = tmc_enable_pin;
dev_addr = tmc_dev_addr;
logger = tmc_logger;
Init();
}
TMC2226::TMC2226(uart_port_t tmc_uart_num, int tmc_tx_pin, int tmc_rx_pin, gpio_num_t tmc_enable_pin, uint8_t tmc_dev_addr, Logger *tmc_logger) {
uart_num = tmc_uart_num;
rx_pin = tmc_rx_pin;
tx_pin = tmc_tx_pin;
enable_pin = tmc_enable_pin;
dev_addr = tmc_dev_addr;
logger = tmc_logger;
Init();
}
void TMC2226::Init(void) {
int status;
// Set up the UART for communication with the device
// tmc_uart = UART(uart_num, tx_pin, rx_pin, 1024, 1024, status, logger);
// printf ("uart status %d\n", status);
tmc_uart = new UART(UART_NUM_1, 17, 18, 1024, 1024, status, logger);
printf ("uart status = %d\n", status);
#ifdef NODEF
int write_ret_val;
static const char *buffer = "A write to UART 0\r\n";
write_ret_val = tmc_uart->Write(buffer, strlen(buffer));
printf ("Wrote %d bytes to UART\n", write_ret_val);
#endif
// TMC2225 enable is active low so indicate that now and enable device
enable_output = CoreLib::GpioOutput { enable_pin, true};
enable_output.on();
// initialize the CRC tables
tmc_fillCRC8Table(0x07, true, 1);
}
int TMC2226::SendDatagram(uint8_t reg_addr, uint32_t value) {
int status = 0;
tx_datagram.all_fields.sync = DATAGRAM_SYNC;
tx_datagram.request_fields.reserved = DATAGRAM_SYNC;
tx_datagram.all_fields.dev_addr = dev_addr;
tx_datagram.all_fields.reg_addr = reg_addr | TMC2226_WRITE_REG;
tx_datagram.data_array[3] = value >> 24;
tx_datagram.data_array[4] = value >> 16;
tx_datagram.data_array[5] = value >> 8;
tx_datagram.data_array[6] = value;
tx_datagram.all_fields.crc = GitHubcalcCRC(tx_datagram.data_array, DATAGRAM_DATARRAY_BYTES_TO_CRC);
status = tmc_uart->Write(tx_datagram.data_array, sizeof(tx_datagram.data_array));
esp_err_t wait_status = tmc_uart->WaitForTX(pdMS_TO_TICKS(10));
if (logger != nullptr) {
logger->Log(Logger::LOG_LEVEL_INFO, "Wrote %d bytes with wait status %d\n", status, wait_status);
logger->SetUseTimeStamp(false);
for (int i = 0; i < sizeof(tx_datagram.all_fields); i++) {
logger->Log(Logger::LOG_LEVEL_INFO, "[%d]0x%x ", i, tx_datagram.data_array[i], status);
}
logger->Log(Logger::LOG_LEVEL_INFO, "\n");
}
vTaskDelay(pdMS_TO_TICKS(5));
return status;
}
int TMC2226::SendDatagram(TMC2226_DATAGRAM &send_datagram){
int status = 0;
tx_datagram.all_fields.sync = DATAGRAM_SYNC;
tx_datagram.request_fields.reserved = DATAGRAM_SYNC;
tx_datagram.all_fields.dev_addr = dev_addr;
tx_datagram.all_fields.reg_addr |= TMC2226_WRITE_REG;
tx_datagram = send_datagram;
tx_datagram.all_fields.crc = tmc_CRC8(tx_datagram.data_array, DATAGRAM_DATARRAY_BYTES_TO_CRC, 1);
status = tmc_uart->Write(tx_datagram.data_array, sizeof(tx_datagram.data_array));
esp_err_t wait_status = tmc_uart->WaitForTX(pdMS_TO_TICKS(10));
if (logger != nullptr) {
logger->Log(Logger::LOG_LEVEL_INFO, "Wrote %d bytes with wait status %d\n", status, wait_status);
logger->SetUseTimeStamp(false);
for (int i = 0; i < sizeof(tx_datagram.all_fields); i++) {
logger->Log(Logger::LOG_LEVEL_INFO, "[%d]0x%x ", i, tx_datagram.data_array[i], status);
}
logger->Log(Logger::LOG_LEVEL_INFO, "\n");
}
vTaskDelay(pdMS_TO_TICKS(5));
return status;
}
int TMC2226::SendReqDatagram(uint8_t reg_addr) {
int status = 0;
tx_datagram.request_fields.sync = DATAGRAM_SYNC;
tx_datagram.request_fields.reserved = DATAGRAM_SYNC;
tx_datagram.request_fields.dev_addr = dev_addr;
// tx_datagram.request_fields.reg_addr = reg_addr | TMC2226_WRITE_REG;
tx_datagram.request_fields.reg_addr = reg_addr;
// tx_datagram.request_fields.crc = tmc_CRC8(tx_datagram.data_array, sizeof(tx_datagram.request_fields), 1);
CalcCRC(tx_datagram.data_array, sizeof(tx_datagram.request_fields));
status = tmc_uart->Write(tx_datagram.data_array, sizeof(sizeof(tx_datagram.request_fields)));
esp_err_t wait_status = tmc_uart->WaitForTX(pdMS_TO_TICKS(10));
if (logger != nullptr) {
logger->Log(Logger::LOG_LEVEL_INFO, "Wrote %d bytes with wait status %d\n", status, wait_status);
logger->SetUseTimeStamp(false);
for (int i = 0; i < sizeof(tx_datagram.request_fields); i++) {
logger->Log(Logger::LOG_LEVEL_INFO, "[%d]0x%x ", i, tx_datagram.data_array[i], status);
}
logger->Log(Logger::LOG_LEVEL_INFO, "\n");
}
vTaskDelay(pdMS_TO_TICKS(5));
return status;
}
int TMC2226::SendRegDatagram(TMC2226_DATAGRAM &req_datagram) {
int status = 0;
tx_datagram.request_fields.sync = DATAGRAM_SYNC;
tx_datagram.request_fields.reserved = DATAGRAM_SYNC;
tx_datagram.request_fields.dev_addr = dev_addr;
tx_datagram.request_fields.reg_addr |= TMC2226_WRITE_REG;
// tx_datagram.request_fields.crc = tmc_CRC8(tx_datagram.data_array, sizeof(tx_datagram.request_fields), 1);
CalcCRC(tx_datagram.data_array, sizeof(tx_datagram.request_fields));
status = tmc_uart->Write(tx_datagram.data_array, sizeof(tx_datagram.request_fields));
esp_err_t wait_status = tmc_uart->WaitForTX(pdMS_TO_TICKS(10));
if (logger != nullptr) {
logger->Log(Logger::LOG_LEVEL_INFO, "Wrote %d bytes with wait status %d\n", status, wait_status);
logger->SetUseTimeStamp(false);
for (int i = 0; i < sizeof(tx_datagram.request_fields); i++) {
logger->Log(Logger::LOG_LEVEL_INFO, "[%d]0x%x ", i, tx_datagram.data_array[i], status);
}
logger->Log(Logger::LOG_LEVEL_INFO, "\n");
}
return status;
}
int TMC2226::ReceiveDataGram(TMC2226_DATAGRAM &recv_datagram){
int status = 0;
status = tmc_uart->Read(recv_datagram.data_array, sizeof(rx_datagram.all_fields), tmc_uart->DelayInMS(100));
if (logger != nullptr) {
logger->Log(Logger::LOG_LEVEL_INFO, "Read %d bytes\n", status);
}
// recv_datagram = rx_datagram;
// TODO check CRC
return status;
}
TMC2226_DATAGRAM TMC2226::GetVersion(void) {
int status = 0;
// Request the data for the version which is in the IOIN register
status = SendReqDatagram(TMC2226_IOIN);
tmc_uart->FlushRxBuffer();
// Give the device a chance to respond
vTaskDelay(pdMS_TO_TICKS(5));
// Get the register data
memset(rx_datagram.data_array, 0, sizeof(rx_datagram.data_array));
status = ReceiveDataGram(rx_datagram);
printf("GetVersion status = %d version = 0x%x\n", status, (uint32_t)rx_datagram.all_fields.sync);
return rx_datagram;
}
maincode.cpp:
#ifdef SERIAL_MOTOR_CONTROL
logger.SetLogLevel(Logger::LOG_LEVEL_VERBOSE);
TMC2226 tmc2226_serial_control (UART_NUM_0, (gpio_num_t)18, (gpio_num_t)17, (gpio_num_t)21, 0, &logger);
tmc2226_serial_control.SendDatagram(0x00, 0x00000141UL);
while(1) {
vTaskDelay(pdMS_TO_TICKS(5000));
tmc2226_serial_control.GetVersion();
}
#endif


