cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 Half-Duplex UART with Interrupts to TMC2209

daniellages
Associate

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:

daniellages_0-1748010574500.png

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

osciloscope_optimized_6000.png

 

Thanks in advance!

0 REPLIES 0