LP-MSPM0G3507: 16x2 LCD Character Display issue

Part Number: LP-MSPM0G3507
Other Parts Discussed in Thread: MSPM0G3507

Tool/software:

I am new to CCS Theia, I am currently trying to interface a 16x2 LCD with the LaunchPad MSPM0G3507 board.
I am not able to make it work perfectly as I tried many different methods across the internet.

The issue I am facing is I am able to print numbers and symbols, but am not able to print any characters.
as you can see in the code i am trying to print both but it doesn't work.

Is is some timing issue that is making it not work or something else.

please let me know any solution if you are able to find it in this or you already know any sample code that will work.

This is my current code which is not working.

/*
 * Copyright (c) 2020, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "ti/devices/msp/m0p/mspm0g350x.h"
#include "ti/driverlib/m0p/dl_core.h"
#include "ti/driverlib/m0p/dl_systick.h"
#include "ti_msp_dl_config.h"
#include <machine/_stdint.h>
#include <sys/_stdint.h>

/* Pin definitions (customize based on your hardware) */
#define RS_PIN GPIO_GRP_0_RS_PIN    // Example: Port 1, Pin 0
#define ENABLE_PIN GPIO_GRP_0_E_PIN // Example: Port 1, Pin 1
#define D4_PIN GPIO_GRP_0_D4_PIN    // Example: Port 1, Pin 2
#define D5_PIN GPIO_GRP_0_D5_PIN    // Example: Port 1, Pin 3
#define D6_PIN GPIO_GRP_0_D6_PIN    // Example: Port 1, Pin 4
#define D7_PIN GPIO_GRP_0_D7_PIN    // Example: Port 1, Pin 5

#define HIGH 1
#define LOW 0

#define LCD_PORT GPIO_GRP_0_PORT // Example: GPIO Port A

#define MAX_TICKS 0xFFFFFF // Maximum ticks for SysTick (24-bit)

/* Function prototypes */
void delayMiliseconds(uint32_t milliseconds);
void delayMicroseconds(uint32_t microseconds);
void digitalWrite(uint32_t pins, uint8_t state);

// Function prototypes
void LCD_Command(unsigned char cmd);
void LCD_Data(unsigned char data);
void LCD_Init(void);
void LCD_String(char *str);
void LCD_Clear();

int main(void) {
  SYSCFG_DL_init();
  LCD_Init();

  while (1) {
    DL_GPIO_togglePins(GPIO_GRP_1_PORT, GPIO_GRP_1_PIN_0_PIN);
    delayMiliseconds(3000);
    LCD_String("88");
    LCD_Data(41); // Corresponding to 'A' in 4-bit mode
    delayMiliseconds(3000);
    LCD_Clear();
  }
}

void delayMiliseconds(uint32_t milliseconds) {
  uint32_t ticks_per_ms = CPUCLK_FREQ / 1000;
  uint32_t max_delay_ms = MAX_TICKS / ticks_per_ms;

  while (milliseconds > 0) {
    uint32_t delayMiliseconds =
        (milliseconds > max_delay_ms) ? max_delay_ms : milliseconds;
    uint32_t ticks = delayMiliseconds * ticks_per_ms;

    DL_SYSTICK_init(ticks);
    DL_SYSTICK_enable();

    // Wait until the COUNTFLAG is set
    while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0)
      ;

    DL_SYSTICK_disable();

    milliseconds -= delayMiliseconds;
  }
}

void delayMicroseconds(uint32_t microseconds) {

  uint32_t ticks = microseconds * (CPUCLK_FREQ / 1000000);

  // Ensure the reload value is within 24-bit range
  if (ticks > 0xFFFFFF)
    ticks = 0xFFFFFF;

  DL_SYSTICK_init(ticks);

  // Start SysTick
  DL_SYSTICK_enable();

  // Wait until the COUNTFLAG is set
  while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0)
    ;

  // Stop SysTick
  DL_SYSTICK_disable();
}

void digitalWrite(uint32_t pins, uint8_t state) {
  if (state == HIGH) {
    DL_GPIO_setPins(LCD_PORT, pins);
  } else if (state == LOW) {
    DL_GPIO_clearPins(LCD_PORT, pins);
  } else {
  }
}

void LCD_Command(unsigned char cmd) {
  // Send the higher nibble
  digitalWrite(D4_PIN, (cmd & 0x10) >> 4);
  digitalWrite(D5_PIN, (cmd & 0x20) >> 5);
  digitalWrite(D6_PIN, (cmd & 0x40) >> 6);
  digitalWrite(D7_PIN, (cmd & 0x80) >> 7);
  digitalWrite(RS_PIN, LOW); // Command mode
  digitalWrite(ENABLE_PIN, HIGH);
  delayMicroseconds(1);
  digitalWrite(ENABLE_PIN, LOW);
  delayMicroseconds(1);

  // Send the lower nibble
  digitalWrite(D4_PIN, cmd & 0x01);
  digitalWrite(D5_PIN, (cmd & 0x02) >> 1);
  digitalWrite(D6_PIN, (cmd & 0x04) >> 2);
  digitalWrite(D7_PIN, (cmd & 0x08) >> 3);
  digitalWrite(ENABLE_PIN, HIGH);
  delayMicroseconds(1);
  digitalWrite(ENABLE_PIN, LOW);
  delayMicroseconds(30);
}

void LCD_Data(unsigned char data) {
  // Send the higher nibble
  digitalWrite(D4_PIN, (data & 0x10) >> 4);
  digitalWrite(D5_PIN, (data & 0x20) >> 5);
  digitalWrite(D6_PIN, (data & 0x40) >> 6);
  digitalWrite(D7_PIN, (data & 0x80) >> 7);

  digitalWrite(RS_PIN, HIGH); // Data mode
  digitalWrite(ENABLE_PIN, HIGH);
  delayMicroseconds(1);
  digitalWrite(ENABLE_PIN, LOW);
  delayMicroseconds(1);

  // Send the lower nibble
  digitalWrite(D4_PIN, data & 0x01);
  digitalWrite(D5_PIN, (data & 0x02) >> 1);
  digitalWrite(D6_PIN, (data & 0x04) >> 2);
  digitalWrite(D7_PIN, (data & 0x08) >> 3);

  digitalWrite(ENABLE_PIN, HIGH);
  delayMicroseconds(1);
  digitalWrite(ENABLE_PIN, LOW);
  delayMicroseconds(30);
}


void LCD_Init(void) {
  delayMiliseconds(50);
  digitalWrite(RS_PIN, LOW);     // RS = 0
  digitalWrite(ENABLE_PIN, LOW); // EN = 0
//   // Initialize LCD in 4-bit mode
  LCD_Command(0x02); // Function set: Initialize
  LCD_Command(0x28); // Function set: 4-bit mode
  LCD_Command(0x01); // 2-line display, 5x8 dots
  LCD_Command(0x0c); // Display ON, Cursor OFF, Blink OFF
  LCD_Command(0x06); // Entry mode: Increment cursor
}

void LCD_String(char *str) {
  while (*str) {
    LCD_Data(*str++);
  }
}

void LCD_Clear() {
  LCD_Command(0x01); /*clear display screen*/
  delayMiliseconds(3);
}


Please guide me through this.

Thankyou

  • I found the issue, it was related to the timing of the commands.
    I am attaching the updated code.

    /*
     * Copyright (c) 2020, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include "ti/devices/msp/m0p/mspm0g350x.h"
    #include "ti/driverlib/m0p/dl_core.h"
    #include "ti/driverlib/m0p/dl_systick.h"
    #include "ti_msp_dl_config.h"
    #include <machine/_stdint.h>
    #include <sys/_stdint.h>
    
    /* Pin definitions (customize based on your hardware) */
    #define RS_PIN GPIO_GRP_0_RS_PIN    // Example: Port 1, Pin 0
    #define ENABLE_PIN GPIO_GRP_0_E_PIN // Example: Port 1, Pin 1
    #define D4_PIN GPIO_GRP_0_D4_PIN    // Example: Port 1, Pin 2
    #define D5_PIN GPIO_GRP_0_D5_PIN    // Example: Port 1, Pin 3
    #define D6_PIN GPIO_GRP_0_D6_PIN    // Example: Port 1, Pin 4
    #define D7_PIN GPIO_GRP_0_D7_PIN    // Example: Port 1, Pin 5
    
    #define HIGH 1
    #define LOW 0
    
    #define LCD_PORT GPIO_GRP_0_PORT // Example: GPIO Port A
    
    #define MAX_TICKS 0xFFFFFF // Maximum ticks for SysTick (24-bit)
    
    /* Function prototypes */
    void delayMiliseconds(uint32_t milliseconds);
    void delayMicroseconds(uint32_t microseconds);
    void digitalWrite(uint32_t pins, uint8_t state);
    
    // Function prototypes
    void LCD_Command(unsigned char cmd);
    void LCD_Data(unsigned char data);
    void LCD_Init(void);
    void LCD_String(char *str);
    void LCD_Clear();
    
    int main(void) {
      SYSCFG_DL_init();
      LCD_Init();
    
      while (1) {
        DL_GPIO_togglePins(GPIO_GRP_1_PORT, GPIO_GRP_1_PIN_0_PIN);
        delayMiliseconds(3000);
        LCD_String("Hello Abhinav");
        delayMiliseconds(3000);
        LCD_Clear();
      }
    }
    
    void delayMiliseconds(uint32_t milliseconds) {
      uint32_t ticks_per_ms = CPUCLK_FREQ / 1000;
      uint32_t max_delay_ms = MAX_TICKS / ticks_per_ms;
    
      while (milliseconds > 0) {
        uint32_t delayMiliseconds =
            (milliseconds > max_delay_ms) ? max_delay_ms : milliseconds;
        uint32_t ticks = delayMiliseconds * ticks_per_ms;
    
        DL_SYSTICK_init(ticks);
        DL_SYSTICK_enable();
    
        // Wait until the COUNTFLAG is set
        while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0)
          ;
    
        DL_SYSTICK_disable();
    
        milliseconds -= delayMiliseconds;
      }
    }
    
    void delayMicroseconds(uint32_t microseconds) {
    
      uint32_t ticks = microseconds * (CPUCLK_FREQ / 1000000);
    
      // Ensure the reload value is within 24-bit range
      if (ticks > 0xFFFFFF)
        ticks = 0xFFFFFF;
    
      DL_SYSTICK_init(ticks);
    
      // Start SysTick
      DL_SYSTICK_enable();
    
      // Wait until the COUNTFLAG is set
      while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0)
        ;
    
      // Stop SysTick
      DL_SYSTICK_disable();
    }
    
    void digitalWrite(uint32_t pins, uint8_t state) {
      if (state == HIGH) {
        DL_GPIO_setPins(LCD_PORT, pins);
      } else if (state == LOW) {
        DL_GPIO_clearPins(LCD_PORT, pins);
      } else {
      }
    }
    
    void LCD_Command(unsigned char cmd) {
      // Send the higher nibble
      digitalWrite(D4_PIN, (cmd & 0x10) >> 4);
      delayMicroseconds(1);
      digitalWrite(D5_PIN, (cmd & 0x20) >> 5);
      delayMicroseconds(1);
      digitalWrite(D6_PIN, (cmd & 0x40) >> 6);
      delayMicroseconds(1);
      digitalWrite(D7_PIN, (cmd & 0x80) >> 7);
      delayMicroseconds(1);
      digitalWrite(RS_PIN, LOW); // Command mode
      delayMicroseconds(1);
      digitalWrite(ENABLE_PIN, HIGH);
      delayMicroseconds(1);
      digitalWrite(ENABLE_PIN, LOW);
      delayMicroseconds(1);
    
      // Send the lower nibble
      digitalWrite(D4_PIN, cmd & 0x01);
      delayMicroseconds(1);
      digitalWrite(D5_PIN, (cmd & 0x02) >> 1);
      delayMicroseconds(1);
      digitalWrite(D6_PIN, (cmd & 0x04) >> 2);
      delayMicroseconds(1);
      digitalWrite(D7_PIN, (cmd & 0x08) >> 3);
      delayMicroseconds(1);
      digitalWrite(ENABLE_PIN, HIGH);
      delayMicroseconds(1);
      digitalWrite(ENABLE_PIN, LOW);
      delayMicroseconds(30);
    }
    
    void LCD_Data(unsigned char data) {
      // Send the higher nibble
      digitalWrite(D4_PIN, (data & 0x10) >> 4);
      delayMicroseconds(1);
      digitalWrite(D5_PIN, (data & 0x20) >> 5);
      delayMicroseconds(1);
      digitalWrite(D6_PIN, (data & 0x40) >> 6);
      delayMicroseconds(1);
      digitalWrite(D7_PIN, (data & 0x80) >> 7);
      delayMicroseconds(1);
    
      digitalWrite(RS_PIN, HIGH); // Data mode
      digitalWrite(ENABLE_PIN, HIGH);
      delayMicroseconds(1);
      digitalWrite(ENABLE_PIN, LOW);
      delayMicroseconds(1);
    
      // Send the lower nibble
      digitalWrite(D4_PIN, data & 0x01);
      delayMicroseconds(1);
      digitalWrite(D5_PIN, (data & 0x02) >> 1);
      delayMicroseconds(1);
      digitalWrite(D6_PIN, (data & 0x04) >> 2);
      delayMicroseconds(1);
      digitalWrite(D7_PIN, (data & 0x08) >> 3);
      delayMicroseconds(1);
    
      digitalWrite(ENABLE_PIN, HIGH);
      delayMicroseconds(1);
      digitalWrite(ENABLE_PIN, LOW);
      delayMicroseconds(30);
    }
    
    void LCD_Init(void) {
      delayMiliseconds(50);
      digitalWrite(RS_PIN, LOW);     // RS = 0
      digitalWrite(ENABLE_PIN, LOW); // EN = 0
      // Initialize LCD in 4-bit mode
      LCD_Command(0x02); // Function set: Initialize
      LCD_Command(0x28); // Function set: 4-bit mode
      LCD_Command(0x01); // 2-line display, 5x8 dots
      LCD_Command(0x0c); // Display ON, Cursor OFF, Blink OFF
      LCD_Command(0x06); // Entry mode: Increment cursor
    
      delayMiliseconds(2);
      LCD_Command(0x80); /* Cursor 1st row 0th position */
    }
    
    void LCD_String(char *str) {
      while (*str) {
        LCD_Data(*str++);
      }
    }
    
    void LCD_Clear() {
      LCD_Command(0x01); /*clear display screen*/
      delayMiliseconds(3);
    }