Skip to main content
Visitor II
December 10, 2024
Question

lcd1602+i2c+nucleo f401re don't work on stm32cubeide but works on keil uvision

  • December 10, 2024
  • 3 replies
  • 1045 views

I run the same code with the same .ioc between stme32cubeide and keil uvision but lcd only show on keil and it shows nothing on cubeide. Anyone know why?
I use register due to requirement of my teacher.
Thank you!

#include "stm32f4xx.h"
#inclide < stdio.h>

#define LCD_ADDR (0x27 << 1)
#define LCD_EN 0x04
#define LCD_RS 0x01

void Timer2_Init(void)
{
 // Clock enable
 RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
}

void delay_us(uint32_t us)
{
 // Prescaler
 TIM2->PSC = 16 - 1;

 // Auto-reload value
 TIM2->ARR = us;

 // Forced update
 TIM2->EGR = TIM_EGR_UG;

 // Clear update flag
 TIM2->SR &= ~TIM_SR_UIF;

 // Timer enable
 TIM2->CR1 |= TIM_CR1_CEN;
 while (!(TIM2->SR & TIM_SR_UIF))
 ; // wait till update flag is set

 // Clear update flag
 TIM2->SR &= ~TIM_SR_UIF;

 // Stop timer
 TIM2->CR1 &= ~TIM_CR1_CEN;
}

void I2C_Init(void)
{
 // Clock
 RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
 RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;

 // Analog mode
 GPIOB->MODER |= GPIO_MODER_MODER8_1 | GPIO_MODER_MODER9_1;

 // Open drain
 GPIOB->OTYPER |= GPIO_OTYPER_OT_8 | GPIO_OTYPER_OT_9;

 // High speed output
 GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8 | GPIO_OSPEEDER_OSPEEDR9;

 // Pull up resistor
 GPIOB->PUPDR |= GPIO_PUPDR_PUPDR8_0 | GPIO_PUPDR_PUPDR9_0;

 // Alternative function for i2c
 GPIOB->AFR[1] |= (4 << (4 * 0)) | (4 << (4 * 1));

 // Reset I2C
 I2C1->CR1 |= (1 << 15);
 I2C1->CR1 &= ~(1 << 15);

 // I2C clock bus
 I2C1->CR2 |= (42 << 0);
 I2C1->CCR = 210 << 0;
 I2C1->TRISE = 43;

 // I2C enable
 I2C1->CR1 |= I2C_CR1_PE;
}

void I2C_SendData(uint8_t address, uint8_t data)
{
 // Acknowlegde enable
 I2C1->CR1 |= I2C_CR1_ACK;

 // Send start signal
 I2C1->CR1 |= I2C_CR1_START;
 while (!(I2C1->SR1 & I2C_SR1_SB))
 ; // wait for start condition generation

 // Send slave address
 I2C1->DR = address;
 while (!(I2C1->SR1 & I2C_SR1_ADDR))
 ; // wait for address matched

 // Dummy read the register to clear it before sending data
 (void)I2C1->SR1;
 (void)I2C1->SR2;

 // Send data
 while (!(I2C1->SR1 & I2C_SR1_TXE))
 ; // wait for data register is empty
 I2C1->DR = data;
 while (!(I2C1->SR1 & I2C_SR1_BTF))
 ; // wait for byte transfer

 // Send stop signal
 I2C1->CR1 |= I2C_CR1_STOP;
}

void LCD_SendCmd(uint8_t cmd)
{
 uint8_t 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=0, rs=0
 data_t[3] = data_l | 0x08; // en=1, rs=0
 for (int i = 0; i < 4; i++)
 {
 I2C_SendData(LCD_ADDR, data_t[i]);
 delay_us(20);
 }
}

void LCD_SendData(uint8_t data)
{
 uint8_t 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
 for (int i = 0; i < 4; i++)
 {
 I2C_SendData(LCD_ADDR, data_t[i]);
 delay_us(20);
 }
}

void LCD_Init(void)
{
 LCD_SendCmd(0x33); // LCD 4-bit mode
 delay_us(10000);
 LCD_SendCmd(0x32); // LCD 4-bit mode
 delay_us(2000);
 LCD_SendCmd(0x06); // Cursor position auto increment after a character write
 delay_us(2000);
 LCD_SendCmd(0x0C); // No cursor and cursor blinking
 delay_us(2000);
 LCD_SendCmd(0x28); // 2 line mode and 5x8 mode
 delay_us(2000);
 LCD_SendCmd(0x01); // Clear screen
 delay_us(2000);
}

void LCD_PutString(char *string, int line)
{
 if (line == 1)
 {
 LCD_SendCmd(0x80); // First line
 }
 else
 {
 LCD_SendCmd(0xC0); // Second line
 }
 while (*string)
 {
 LCD_SendData((uint8_t)(*string));
 string++;
 }
}

void LCD_PutStringFloat(char *string, float value, int line)
{
 char buffer[32];
 sprintf(buffer, "%s%.1f", string, value);
 LCD_PutString(buffer, line);
}

int main()
{
 Timer2_Init();
 I2C_Init();
 LCD_Init();
 delay_us(100000);
 LCD_PutString("Hello", 1);
 while (1)
 {
 }
}

 

3 replies

Andrew Neil
Super User
December 10, 2024

Have you used an oscilloscope and/or logic analyser to compare what's happening on the wires in the 2 cases?

Have you used the debuggers in the IDEs to compare what's happening within the code in the 2 cases?

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Pavel A.
Super User
December 10, 2024

Is using CubeIDE a requirement? Otherwise just use Keil and be happy.

There are differences in runtime libraries, compiler-specific behaviors (optimization) and so on. Save your time and nerve cells for the meaningful part of your project.

 

Andrew Neil
Super User
December 10, 2024

This is true but, when a project works on one IDE and not another, that's usually an indicator of problems in the code...

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Tesla DeLorean
Guru
December 10, 2024

Nothing particularly is jumping out in a KEIL vs GNU sense

I'd probably simplify the micro-second delay stuff to initialize the counter once, in maximal 32-bit mode and then observe the delta in TIM2->CNT

Check the peripheral registers in one vs the other.

Check the I2C traffic with a logic-analyzer, type to understand if the issue is one of timing or signalling.

Confirm it's executing.

Ideally have a serial connection or SWV working so you can output diagnostic info in real-time

 

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