2025-05-23 8:05 AM
I'm working on a project using STM32U5 and I'm trying to communicate with a TMC2209 stepper driver over UART in single-wire (half-duplex) mode. This is the connections:
In order to test the connection I'm trying to read the IFCNT values of the driver, which is the register in TMC2209 frame counter used to track how many valid UART datagrams the driver has received since power-on. This is my code:
/* USER CODE BEGIN PV */
volatile uint8_t tx_done = 0;
volatile uint8_t rx_done = 0;
uint8_t tmc2209_rx_buf[8];
/* USER CODE END PV */
/* USER CODE BEGIN 0 */
uint8_t TMC2209_calcCRC(uint8_t* datagram, uint8_t datagramLength) {
uint8_t crc = 0;
uint8_t currentByte;
for(uint8_t i=0; i<datagramLength; i++) {
currentByte = datagram[i];
for(uint8_t j=0; j<8; j++) {
if((crc >> 7) ^ (currentByte & 0x01)) {
crc = (crc << 1) ^ 0x07;
} else {
crc <<= 1;
}
currentByte >>= 1;
}
}
return crc;
}
void TMC2209_WriteRegister(uint8_t reg, uint32_t data) {
uint8_t datagram[8];
datagram[0] = 0x05; // Sync & Reserved
datagram[1] = 0x00; // Slave addr
datagram[2] = reg | 0x80; // Write addr
// Data payload
datagram[3] = (data >> 24) & 0xFF;
datagram[4] = (data >> 16) & 0xFF;
datagram[5] = (data >> 8) & 0xFF;
datagram[6] = data & 0xFF;
datagram[7] = TMC2209_calcCRC(datagram, 7); // CRC
// Reset transmit completion flag
tx_done = 0;
// Transmit using interrupt
if (HAL_UART_Transmit_IT(&huart3, datagram, 8) != HAL_OK) {
printf("TX start failed in WriteRegister!\r\n");
return;
}
printf("Writing to reg 0x%02X: ", reg);
for (int i = 0; i < 8; i++) printf("0x%02X ", datagram[i]);
printf("\r\n");
// Wait until TX is complete
while (!tx_done) {}
}
uint8_t TMC2209_Read_IFCNT(void) {
uint8_t request[4];
uint32_t val = 0;
request[0] = 0x05; // Sync
request[1] = 0x00; // Address
request[2] = 0x02; // IFCNT register
request[3] = TMC2209_calcCRC(request, 3);
rx_done = 0;
tx_done = 0;
if(HAL_UART_Receive_IT(&huart3, tmc2209_rx_buf, 8) != HAL_OK) {
printf("RX IT start failed\r\n");
return 0xFD;
}
HAL_Delay(1);
if(HAL_UART_Transmit_IT(&huart3, request, 4) != HAL_OK) {
printf("TX IT start failed\r\n");
return 0xFE;
}
while(!rx_done);
if (TMC2209_calcCRC(tmc2209_rx_buf, 7) != tmc2209_rx_buf[7]) {
printf("CRC mismatch: got 0x%02X, expected 0x%02X\r\n",
tmc2209_rx_buf[7],
TMC2209_calcCRC(tmc2209_rx_buf, 7));
return 0xFC;
}
if((tmc2209_rx_buf[2] & 0x7F) != 0x02) {
printf("Register mismatch\r\n");
return 0xFB;
}
val = (tmc2209_rx_buf[3] << 24) |
(tmc2209_rx_buf[4] << 16) |
(tmc2209_rx_buf[5] << 8) |
tmc2209_rx_buf[6];
return (uint8_t)(val & 0xFF);
}
void test_IFCNT(void) {
uint8_t last = TMC2209_Read_IFCNT();
printf("Initial IFCNT: %d\r\n", last);
for(int i=0; i<5; i++) {
TMC2209_WriteRegister(0x10, 0);
HAL_Delay(5);
uint8_t now = TMC2209_Read_IFCNT();
printf("IFCNT after write %d: %d\r\n", i+1, now);
HAL_Delay(2);
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if(huart == &huart3) {
printf("Received complete!\r\n");
for(int i=0; i<8; i++)
printf("0x%02X ", tmc2209_rx_buf[i]);
printf("\r\n");
rx_done = 1;
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
if(huart == &huart3) {
tx_done = 1;
printf("TX complete\r\n");
}
}
/* USER CODE END 0 */
in the main then I just call the function "test_IFCNT();"
This is the full output
Starting...
TX complete
Received complete!
0x05 0x00 0x02 0x8F 0x05 0xFF 0x02 0x00
CRC mismatch: got 0x00, expected 0xAE
Initial IFCNT: 252
Writing to reg 0x10: 0x05 0x00 0x90 0x00 0x00 0x00 0x00 0x50
TX complete
TX complete
This is the osciloscope result
Thanks in advance!