2022-07-26 08:38 AM
Hi there. I'm trying to configure an LCD display in 4-bit mode, which is connected to an I2C expansion chip. I am able to scan and find the I2C address to send commands to, so I assume that means my I2C handler is set up correctly. However, I am very unfamiliar with programming STM32 still.
I followed some online guides for setup, but when I issue commands to the LCD, nothing happens. There's no initialization in response to the display commands sent, and there's no string that appears on the LCD when sending data. I need some guidance on getting the I2C and LCD to work.
Below are my parts and their associated data sheets, my current code, and I've attached some screenshots of my schematic.
Note: SCL is on pin PB9. SDA is on PB8.
My Parts and their Datasheets
main.c
#include "string.h"
#include "main.h"
#include "motorcontrol.h"
#include "STEVAL_ESC001V1.h"
// ...
#define LCD_I2C_ADDR 0x20
// ...
UART_HandleTypeDef huart1;
I2C_HandleTypeDef hi2c1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
// ...
static void MX_I2C1_Init(void);
static void lcd_send_cmd(char cmd);
static void lcd_send_data(char data);
static void lcd_init(void);
static void lcd_send_string(char *str);
static void scan_i2c(void);
int main(void)
{
// ...
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
// ...
MX_USART1_UART_Init();
// ...
MX_I2C1_Init();
/* Initialize interrupts */
MX_NVIC_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Transmit(&huart1, (uint8_t *) StartMSG, strlen(StartMSG), 2000);
lcd_init();
lcd_send_string("Hello");
ESCboot();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
PWM_FC_control();
}
/* USER CODE END 3 */
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_TIM1|RCC_PERIPHCLK_I2C1;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
PeriphClkInit.Tim1ClockSelection = RCC_TIM1CLK_HCLK;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
// ...
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x2000090E;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
/*Configure GPIO pins : PB2 PB3 */
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// Init the led pins to off (high is off, low is on)
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15, GPIO_PIN_SET);
// config the RGB led drive pins
GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // digital Output
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
// Configure charge status input pins
GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // digital Input
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
static void lcd_send_cmd(char cmd)
{
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, LCD_I2C_ADDR, (uint8_t *) data_t, 4, 100);
}
static 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=1
data_t[1] = data_u|0x09; //en=0, rs=1
data_t[2] = data_l|0x0D; //en=1, rs=1
data_t[3] = data_l|0x09; //en=0, rs=1
HAL_I2C_Master_Transmit (&hi2c1, LCD_I2C_ADDR, (uint8_t *) data_t, 4, 100);
}
static void lcd_init(void)
{
// 4 bit initialisation
uint8_t temp[] = "\nStarting 4 bit initialization of LCD...\n";
HAL_UART_Transmit(&huart1, (uint8_t *) temp, strlen(temp), 2000);
HAL_Delay(50); // wait for >40ms
lcd_send_cmd (0x30);
HAL_Delay(30); // wait for >4.1ms
lcd_send_cmd (0x30);
HAL_Delay(10); // wait for >100us
lcd_send_cmd (0x30);
HAL_Delay(10);
lcd_send_cmd (0x20); // 4bit mode
HAL_Delay(10);
// dislay initialisation
lcd_send_cmd (0x20); // Function set --> DL=0 (4 bit mode), N = 0 (1 line display) F = 0 (5x8 characters)
HAL_Delay(1);
lcd_send_cmd (0x08); //Display on/off control --> D=0,C=0, B=0 ---> display off
HAL_Delay(1);
lcd_send_cmd (0x01); // clear display
HAL_Delay(1);
lcd_send_cmd (0x10); //Set cursor
HAL_Delay(1);
lcd_send_cmd (0x06); //Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift)
HAL_Delay(1);
lcd_send_cmd (0x0C); //Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits)
}
static void lcd_send_string(char *str)
{
uint8_t temp[] = "Attempting to send string to LCD: ";
HAL_UART_Transmit(&huart1, (uint8_t *) temp, strlen(temp), 2000);
// HAL_UART_Transmit(&huart1, (uint8_t *) str, strlen(str), 2000);
// for (uint8_t i = 0; i < strlen(str); i++) {
// HAL_UART_Transmit(&huart1, str[i], strlen(str[i]), 2000);
// lcd_send_data(str[i]);
// }
while (*str) {
const uint8_t c = *str++;
HAL_UART_Transmit(&huart1, c, strlen(c), 2000);
lcd_send_data(c);
}
}
static void scan_i2c(void)
{
uint8_t i = 0, ret;
/*-[ I2C Bus Scanning ]-*/
HAL_UART_Transmit(&huart1, StartMSG, strlen(StartMSG), 10000);
for(i=1; i<128; i++)
{
ret = HAL_I2C_IsDeviceReady(&hi2c1, (uint16_t)(i<<1), 3, 5);
if (ret != HAL_OK) /* No ACK Received At That Address */
{
HAL_UART_Transmit(&huart1, Space, strlen(Space), 10000);
}
else if(ret == HAL_OK)
{
sprintf(Buffer, "0x%X", i);
HAL_UART_Transmit(&huart1, Buffer, strlen(Buffer), 10000);
}
}
HAL_UART_Transmit(&huart1, EndMSG, strlen(EndMSG), 10000);
/*--[ Scanning Done ]--*/
}
I am still new at programming on this platform. In addition to any answers, if you know of any straightforward resources that will help me learn more, please provide pointers where to find them.
2022-07-26 01:13 PM
Here you can find a helping hand for your learning projects.