cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_UART_Receive_IT not resetting after HAL_UART_Transmit

jlaufer
Associate II

I am trying to implement MODBUS protocol. STM32 receives an initial message of 8 bytes and then send a response of 8 bytes. However, the next message received by the STM32 doesn't trigger the HAL_UART_Receive_IT callback.

 

uint8_t reception_complete = FALSE; // turns true when a MODBUS command is received
uint8_t response[8];
uint8_t response_ready = FALSE;

int main(void)
{	
    while (1)
	{
		// Hang until a MODBUS message is received (8 bytes)
		while(reception_complete != TRUE)
		{
			HAL_UART_Receive_IT(&huart2, &recvd_data, 1);
			if (response_ready == TRUE)
			{
				//send the response back to the master (blocking mode)
				uint16_t resp_len = sizeof(response);
				HAL_UART_Transmit(&huart2, (uint8_t*)response, resp_len, HAL_MAX_DELAY);
				response_ready = FALSE;
			}
	     }
    }
}

 

jlaufer_0-1710358749228.png

 

3 REPLIES 3

Don't create these false interdependencies...

HAL_UART_Transmit() blocks.

Have your receive callback light off the next HAL_UART_Receive_IT() so you don't miss it, but first move the received data into a holding buffer that's not going to be overwritten by the inbound data should more of that arrive in the mean time while you're ignoring it. ie >resp_len byte times..

 

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

That's actually how I had it originally but changed it because I thought maybe calling HAL_UART_Transmit() from HAL_UART_Receive_IT() could have been causing the issue. 

 

I put it back to how it was with the exact same result. I placed breakpoints and I can see that execution is making it to the HAL_UART_Receive_IT(&huart2, &recvd_data, 1); but it just isn't jumping to the Interrupt after HAL_UART_Transmit() is called.

 

//MODBUS params
uint8_t data_buffer[100];
uint8_t recvd_data; //will hold bytes received on RX pin
uint8_t reception_complete = FALSE; // turns true when a MODBUS command is received
uint8_t char_count = 0; // counts up number of bytes received
uint8_t slave_address = 200;
uint8_t modbus_code = 0;
uint8_t response[8];

//values
uint8_t motor1_spd_reg = 0;
uint16_t registers[100];
uint8_t reg_changed[100];

int main(void)
{
	HAL_Init();

	SystemClock_Config(SYS_CLOCK_FREQ_48_MHZ);

	uint32_t clk_freq = Get_PCLK1TIM();

	UART2_Init();

	while (1)
	{
		HAL_UART_Receive_IT(&huart2, &recvd_data, 1);

		// Check and see if there has been any updates to the register values
		if (reg_changed[motor1_spd_reg])
		{
			// pulse = clk_spd * (1 /(2*freq))
			uint32_t pulse_freq = registers[motor1_spd_reg];
			uint32_t pulse = clk_freq * (1 / (2 * pulse_freq));
			//based on the frequency given by the user
			TIMER2_CH1_Init(pulse);
			//Start the timer
			if(HAL_TIM_OC_Start_IT(&htimer2, TIM_CHANNEL_1) != HAL_OK)
			{
				Error_handler();
			}
			reg_changed[motor1_spd_reg] = FALSE;
		}
	}
}

void UART2_Init(void)
{
	huart2.Instance = USART2;
	huart2.Init.BaudRate = 115200;
	huart2.Init.WordLength = UART_WORDLENGTH_8B;
	huart2.Init.StopBits = UART_STOPBITS_1;
	huart2.Init.Parity = UART_PARITY_NONE;
	huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
	huart2.Init.Mode = UART_MODE_TX_RX;
	if (HAL_UART_Init(&huart2) != HAL_OK)
	{
		Error_handler();
	}
}

// count number of received bits and after enough, read MODBUS message
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	data_buffer[char_count] = recvd_data;
	if(char_count == 1)
	{
		modbus_code = recvd_data;
	}
	if (modbus_code < 7 && char_count == 7)
	{
		//8 bytes
		reception_complete = TRUE;
		Decode_MODBUS();
	} else
	{
		if (modbus_code >= 7 && char_count >= 6)
		{
			// For MODBUS messages with codes 7 and up, the 6th byte indicates how many bytes are left in the message
			if (char_count == data_buffer[4] + 8)
			{
				reception_complete = TRUE;
				Decode_MODBUS();
			}
		}
	}
	if (reception_complete == FALSE)
	{
		char_count++;
	}
	else
	{
		char_count = 0;
		reception_complete = FALSE;
	}
}

/***********************************STANDARD MODBUS FUNTIONS ********************************************/
void Decode_MODBUS(void)
{
	if (data_buffer[0] == slave_address)
	{
		// The response begins as an echo
		for (uint8_t i = 0; i<7; i++)
		{
			 response[i] = data_buffer[i];
		}

		response[7] = Calculate_checkSum();

		// Different actions depending on the MODBUS code (2nd byte)
		if (data_buffer[2] == 0)
		{
			//write GPIO
			GPIO_TypeDef *GPIOx;
			if (data_buffer[4] == 0)
				GPIOx = GPIOA;
			if (data_buffer[4] == 1)
				GPIOx = GPIOB;
			if (data_buffer[4] == 2)
				GPIOx = GPIOC;
			if (data_buffer[4] == 3)
				GPIOx = GPIOD;

			uint8_t pinstate;
			if (data_buffer[5] == PIN_HIGH)
			{
				pinstate = GPIO_PIN_SET;
			}
			if (data_buffer[5] == PIN_LOW)
			{
				pinstate = GPIO_PIN_RESET;
			}

			HAL_GPIO_WritePin(GPIOx, data_buffer[3], pinstate);
		}
		if (data_buffer[2] == 1)
		{
			//read GPIO
			GPIO_TypeDef *GPIOx;
			if (data_buffer[4] == 0)
				GPIOx = GPIOA;
			if (data_buffer[4] == 1)
				GPIOx = GPIOB;
			if (data_buffer[4] == 2)
				GPIOx = GPIOC;
			if (data_buffer[4] == 3)
				GPIOx = GPIOD;

			response[5] = HAL_GPIO_ReadPin(GPIOx, data_buffer[3]);
		}
		if (data_buffer[2] == 2)
		{
			//write value
			uint8_t reg_num = data_buffer[3];
			uint8_t data1 = data_buffer[4];
			uint8_t data2 = data_buffer[5];
			registers[reg_num] = data2 * 256 + data1;

		}
		if (data_buffer[2] == 3)
		{
			//read value
			uint8_t reg_num = data_buffer[3];
			response[4] = registers[reg_num] / 256;
			response[5] = registers[reg_num] - (data_buffer[3] * 256);
			reg_changed[reg_num] = TRUE;
		}
		if (data_buffer[2] == 4)
		{
			//set pin mode
			GPIO_TypeDef *GPIOx;
			if (data_buffer[4] == 0)
				GPIOx = GPIOA;
			if (data_buffer[4] == 1)
				GPIOx = GPIOB;
			if (data_buffer[4] == 2)
				GPIOx = GPIOC;
			if (data_buffer[4] == 3)
				GPIOx = GPIOD;
			if (data_buffer[4] == 4)
				GPIOx = GPIOF;

			GPIO_Init(GPIOx, data_buffer[3], data_buffer[5]);

		}
		if (data_buffer[2] == 6)
		{
			//read analog data
		}

		//send the response back to the master (blocking mode)
		uint16_t resp_len = sizeof(response);
		HAL_UART_Transmit(&huart2, (uint8_t*)response, resp_len, HAL_MAX_DELAY);

	} else {
		//nothing will happen (message is discarded)
	}
}

 

After looking closer, it seems like huart->RxState is getting suck in HAL_UART_STATE_BUSY_RX. I don't understand why or how to fix it.

Even if I do 1 Tx/Rx then wait a really long time (a minute) then do another, then I send a Tx to the STM32, the RX gets stuck in this busy state.