cancel
Showing results for 
Search instead for 
Did you mean: 

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

veneneux
Associate

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

 

4 REPLIES 4

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?

Pavel A.
Evangelist III

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.

 

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

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