Skip to main content
Visitor II
Dec 10, 2024 3:01 PM UTC
Question

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

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)
 {
 }
}

 

This topic has been closed for replies.

4 replies

Andrew Neil
Super User
Dec 10, 2024 3:12 PM UTC

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.
Dec 10, 2024 6:33 PM UTC

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
Dec 10, 2024 6:40 PM UTC

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
Dec 10, 2024 10:38 PM UTC

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 Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..