cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103 issue using I2C and 2x USART with HAL library

RSabl
Associate II

Hello, i'm a begginer in stm programming and i've encountered an issue. I'm using two stm32F103 mcu which are communicating via USART1. One F103 is connected to the PC via USART2, that same device is also connected to I2C LCD 16x2 Display , a matrix keypad (GPIO) and two Hall Flow sensors (TIM4 Input Capture channels). IDE i'm using is Atollic TrueSTUDIO. Also im using HAL_Delay functions for matrix keypad (20ms delay between every readout of button press). I've had an issue where HAL_Delay stucks in an endless loop because of the NVIC priority, i've fixed it by raising the NVIC priority of I2C, UART, TIM4 interupts. Both UARTS are in interrupt mode. MCU is working at 72MHz.

While im working in debugging mode, I2C LCD display functions normally but UART is sending giberish. When i disconect the STLINKV2 and connect the STM32 to the power supply, UART works properly , but the LCD display is blank showing gibberish. Anyone has any idea why this could happen, and why does the same code in debugg mode works differently from the realtime mode of operation?

2 REPLIES 2
Bob S
Principal

> I've had an issue where HAL_Delay stucks in an endless loop because of the NVIC priority,

It sounds like you are calling HAL_Delay() from inside your interrupt routines. Usually a bad idea. Interrupts should be short and quick (HAL USB code not withstanding). Using HAL_Delay() in an interrupt routine will delay responses to same or lower priority interrupts (i.e. possibly interfere with interrupt driven UART Rx and cause you to miss data).

So what debug steps have you taken, other than running with and without the STLINK? Have you set breakpoints in the functions that are sending gibberish? Have you tries getting your code to work with one or two peripherals at a time, then build from there? Where is the UART supposed to get the data that it sends?

Otherwise, without seeing you code we're just taking pot shots in the dark. Can you post the relevant portions of your code?

I'm using Hal Delay only in main. I'll post the code here.

This is while loop.

 while (1)
  {
 
  /* USER CODE END WHILE */
	  // Get key pressed
	 	  	 key=KeypadGetKey();
	 	  	 HAL_Delay(50);
	 	  // LCD print
	 	  	 if (text_flag==true)
	 	  	 {
 
	 	   lcd_send_cmd(0x01);
 
	 	  		 if((new_str1 = malloc(strlen(mystr1)+strlen(razina)+1)) != NULL)
	 	  		 {
	 	  			  	      new_str1[0] = '\0';   // ensures the memory is an empty string
	 	  			  	      strcat(new_str1,mystr1);
	 	  			  	      strcat(new_str1,razina);
	 	  		 }
 
 
	 	  	lcd_send_cmd(0x01);
	 	  	lcd_send_string(new_str1);
 
	 	  		 if((new_str2 = malloc(strlen(mystr2)+strlen(curr_lvl)+1)) != NULL)
	 	  		 {
	 	  			  	      new_str2[0] = '\0';   // ensures the memory is an empty string
	 	  			  	      strcat(new_str2,mystr2);
	 	  			  	      strcat(new_str2,curr_lvl);
	 	  		 }
 
	 	  	 lcd_send_cmd(0xC0);
	 	  	 lcd_send_string(new_str2);
	 	  	 }
 
	 	  	  // Numerical key pressed
	 	  	  		if ((key != KEYPAD_NO_PRESSED && (key != '*') ) && (key != KEYPAD_NO_PRESSED && (key!='#')))
	 	  	  		{
	 	  	  			HAL_Delay(30);
	 	  	  			razina[i]=key;
	 	  	  			razina[i+1]='\0';
	 	  	  			i++;
	 	  	  			if(i>2)
	 	  	  			{
	 	  	  				i=0;
	 	  	  			}
	 	  	  			text_flag=true;
	 	  	  		}
	 	  	  	  // Enter (*) pressed
 
	 	  	  		else if(key!=KEYPAD_NO_PRESSED && (key =='*'))
	 	  	  		{
	 	  	  		i=0;
	 	  	  		target_level=atoi(razina);
 
	  /*	  	  	 if((targ_lvl = malloc(strlen(razina))) != NULL)
	 	  	  		  		 {
	 	  	  		  			  	      targ_lvl[0] = '\0';   // ensures the memory is an empty string
	 	  	  		  			  	      strcpy(targ_lvl,razina);
	 	  	  		  		 }
	 */
	 	  	  		text_flag=true;
 
	 	  	  		}
 
	 	  	  		else
	 	  	  		{
	 	  	  			text_flag=false;
	 	  	  		}
  /* USER CODE BEGIN 3 */
 
water_level=getUSART1();
setUSART2(water_level,true);
 
  }
  /* USER CODE END 3 */
 
}
uint32_t getUSART1()
{
	HAL_UART_Receive_IT(&huart1, buffer_USART1_rx, 4);
	uint32_t num=0;
 
	num |= buffer_USART1_rx[0] << 24;
	num |= buffer_USART1_rx[1] << 16;
	num |= buffer_USART1_rx[2] << 8;
	num |= buffer_USART1_rx[3];
 
	return num;
}
uint32_t getUSART2()
{
 
			HAL_UART_Receive_IT(&huart1, buffer_USART1_rx, 4);
				uint32_t num=0;
				num |= buffer_USART2_rx[0] << 24;
				num |= buffer_USART2_rx[1] << 16;
				num |= buffer_USART2_rx[2] << 8;
				num |= buffer_USART2_rx[3];
				return num;
}
void setUSART2(uint32_t value, bool mode)
{
	//mode =TRUE->send RAW uint32, FALSE->send as STRING
 
 
		  if (mode==true)
		  {
			  buffer_USART2_tx[0] = value ;
			  buffer_USART2_tx[1] = value >>8;
			  buffer_USART2_tx[2] = value >> 16;
			  buffer_USART2_tx[3] = value >> 24;
 
			  HAL_UART_Transmit_IT(&huart2,buffer_USART2_tx,4);
		  }
		  else
		  {
			  sprintf(buffer_USART2_tx, "%" PRIu32 "\n",value);
			  	  HAL_UART_Transmit_IT(&huart2,buffer_USART2_tx,5);
		  }
 
}

Above is the USART functions i've written. (since i'm debugging now i've made two options to send it raw and to send it as ASCII uint32)

This is keypad handling.

uint8_t KeypadGetKey()
{
	// Scan column 0 (column 0 pin is grounded, other column pins is open drain)
	HAL_GPIO_WritePin(KEYPAD_GPIO_COL, KEYPAD_PIN_COL0,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(KEYPAD_GPIO_COL, KEYPAD_PIN_COL1,GPIO_PIN_SET);
	HAL_GPIO_WritePin(KEYPAD_GPIO_COL, KEYPAD_PIN_COL2,GPIO_PIN_SET);
	HAL_Delay(5);
	// Read rows
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW0))
		return '1';
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW1))
		return '4';
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW2))
		return '7';
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW3))
		return '*';
	HAL_Delay(20);
	// Scan column 1 (column 1 pin is grounded, other column pins is open drain)
	HAL_GPIO_WritePin(KEYPAD_GPIO_COL, KEYPAD_PIN_COL0,GPIO_PIN_SET);
	HAL_GPIO_WritePin(KEYPAD_GPIO_COL, KEYPAD_PIN_COL1,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(KEYPAD_GPIO_COL, KEYPAD_PIN_COL2,GPIO_PIN_SET);
	HAL_Delay(5);
 
	// Read rows
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW0))
		return '2';
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW1))
		return '5';
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW2))
		return '8';
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW3))
		return '0';
	HAL_Delay(20);
	// Scan column 2 (column 2 pin is grounded, other column pins is open drain)
		HAL_GPIO_WritePin(KEYPAD_GPIO_COL, KEYPAD_PIN_COL0,GPIO_PIN_SET);
		HAL_GPIO_WritePin(KEYPAD_GPIO_COL, KEYPAD_PIN_COL1,GPIO_PIN_SET);
		HAL_GPIO_WritePin(KEYPAD_GPIO_COL, KEYPAD_PIN_COL2,GPIO_PIN_RESET);
		HAL_Delay(5);
	// Read rows
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW0))
		return '3';
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW1))
		return '6';
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW2))
		return '9';
	if (!HAL_GPIO_ReadPin(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW3))
		return '#';
	HAL_Delay(30);
	return KEYPAD_NO_PRESSED;
}

Here are LCD display functions.

#include "i2c-lcd.h"
extern I2C_HandleTypeDef hi2c1;  //I2C handler
#define SLAVE_ADDRESS_LCD 0x7E // LCD address
 
void lcd_send_cmd (char cmd)
{
	  if ( HAL_I2C_IsDeviceReady(&hi2c1,SLAVE_ADDRESS_LCD,3,1000) != HAL_OK) {
 
	   /* Return error */
	   __NOP();
 
	   }
	  else {
 
 
  char data_u, data_l;
	uint8_t data_t[4];
	data_u = (cmd&0xf0);
	data_l = ((cmd<<4)&0xf0);
	data_t[0] = data_u|0x0C;  //en=1, rs=0
	data_t[1] = data_u|0x08;  //en=0, rs=0
	data_t[2] = data_l|0x0C;  //en=1, rs=0
	data_t[3] = data_l|0x08;  //en=0, rs=0
	HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDRESS_LCD,(uint8_t *) data_t, 4, 100);
	HAL_Delay(2);
	  }
}
 
void lcd_send_data (char data)
{
	char data_u, data_l;
	uint8_t data_t[4];
	data_u = (data&0xf0);
	data_l = ((data<<4)&0xf0);
	data_t[0] = data_u|0x0D;  //en=1, rs=0
	data_t[1] = data_u|0x09;  //en=0, rs=0
	data_t[2] = data_l|0x0D;  //en=1, rs=0
	data_t[3] = data_l|0x09;  //en=0, rs=0
	HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDRESS_LCD,(uint8_t *) data_t, 4, 100);
	HAL_Delay(2);
}
 
void lcd_init (void)
{
	lcd_send_cmd (0x02);
	lcd_send_cmd (0x28);
	lcd_send_cmd (0x0c);
	lcd_send_cmd (0x80);
}
 
void lcd_send_string (char *str)
{
	while (*str) lcd_send_data (*str++);
}

Configuration settings of the peripheral are made in STM CUBEMX if you need that too i can post it (USARTS baudrate is 115200 and I2C clock speed is 100000) .Basicly what i'm doing is sending water level value from another STM to this one and just passing it to the PC port and reading the value using Docklight. I've tried just hardcoding a test value and sending it on the PC and it works properly, i've also done that on the other STM so i'm guessing the communcation and pin connection is okay. I'm thinking since i'm powering the LCD with the STM32 3.3V and GND pins maybe the current is too weak to power everything properly. Thank you for your response .