feat: LCD working!

This commit is contained in:
Frederik Beimgraben 2025-07-02 21:21:47 +02:00
parent ab31fe5838
commit 362251773d
12 changed files with 684 additions and 249 deletions

View File

@ -3,6 +3,8 @@ encoding//Debug/driverlib/MSP430FR2xx_4xx/subdir_rules.mk=UTF-8
encoding//Debug/driverlib/MSP430FR2xx_4xx/subdir_vars.mk=UTF-8
encoding//Debug/jsmn/subdir_rules.mk=UTF-8
encoding//Debug/jsmn/subdir_vars.mk=UTF-8
encoding//Debug/latex/subdir_rules.mk=UTF-8
encoding//Debug/latex/subdir_vars.mk=UTF-8
encoding//Debug/makefile=UTF-8
encoding//Debug/objects.mk=UTF-8
encoding//Debug/sources.mk=UTF-8

248
Board.h Normal file
View File

@ -0,0 +1,248 @@
/* --COPYRIGHT--,BSD
* Copyright (c) 2017, 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.
* --/COPYRIGHT--*/
/**
* ===
* Board.h
* ===
* This file is meant to provide generic GPIO selection definitions that allows
* DriverLib to be used portably across different LaunchPads. The same module
* pin might not be populated on the same physical port and pin on different
* LaunchPads.
*
* This file is intended to be modified and updated by individual users based
* on application need. It will be initially populated according to common
* peripherals available on a LaunchPad board, but by all means not complete.
*
* GPIO_PRIMARY_MODULE_FUNCTION indicates Port SEL bits are 01
* GPIO_SECONDARY_MODULE_FUNCTION indicates Port SEL bits are 10
* GPIO_TERNARY_MODULE_FUNCTION indicates Port SEL bits are 11
* If the Port SEL bits are 00, the FUNCTION bits should be ignored
* Please consult device datasheet for more info, under "Input/Output Diagrams"
*
**/
#ifndef __BOARD_H__
#define __BOARD_H__
#ifdef __MSP430FR4133__
#define GPIO_PORT_LED1 GPIO_PORT_P1
#define GPIO_PIN_LED1 GPIO_PIN0
#define GPIO_PORT_LED2 GPIO_PORT_P4
#define GPIO_PIN_LED2 GPIO_PIN0
#define GPIO_PORT_S1 GPIO_PORT_P1
#define GPIO_PIN_S1 GPIO_PIN2
#define GPIO_PORT_ADC7 GPIO_PORT_P1
#define GPIO_PIN_ADC7 GPIO_PIN7
#define GPIO_FUNCTION_ADC7 GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_MCLK GPIO_PORT_P1
#define GPIO_PIN_MCLK GPIO_PIN4
#define GPIO_FUNCTION_MCLK GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_SMCLK GPIO_PORT_P8
#define GPIO_PIN_SMCLK GPIO_PIN0
#define GPIO_FUNCTION_SMCLK GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_ACLK GPIO_PORT_P8
#define GPIO_PIN_ACLK GPIO_PIN1
#define GPIO_FUNCTION_ACLK GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCA0TXD GPIO_PORT_P1
#define GPIO_PIN_UCA0TXD GPIO_PIN0
#define GPIO_FUNCTION_UCA0TXD GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCA0RXD GPIO_PORT_P1
#define GPIO_PIN_UCA0RXD GPIO_PIN1
#define GPIO_FUNCTION_UCA0RXD GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCB0SCL GPIO_PORT_P5
#define GPIO_PIN_UCB0SCL GPIO_PIN3
#define GPIO_FUNCTION_UCB0SCL GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCB0SDA GPIO_PORT_P5
#define GPIO_PIN_UCB0SDA GPIO_PIN2
#define GPIO_FUNCTION_UCB0SDA GPIO_PRIMARY_MODULE_FUNCTION
#endif // __MSP430FR4133__
#ifdef __MSP430FR2311__
#define GPIO_PORT_LED1 GPIO_PORT_P1
#define GPIO_PIN_LED1 GPIO_PIN0
#define GPIO_PORT_LED2 GPIO_PORT_P2
#define GPIO_PIN_LED2 GPIO_PIN0
#define GPIO_PORT_S1 GPIO_PORT_P1
#define GPIO_PIN_S1 GPIO_PIN1
#define GPIO_PORT_ADC7 GPIO_PORT_P1
#define GPIO_PIN_ADC7 GPIO_PIN7
#define GPIO_FUNCTION_ADC7 GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_MCLK GPIO_PORT_P2
#define GPIO_PIN_MCLK GPIO_PIN6
#define GPIO_FUNCTION_MCLK GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_SMCLK GPIO_PORT_P1
#define GPIO_PIN_SMCLK GPIO_PIN0
#define GPIO_FUNCTION_SMCLK GPIO_SECONDARY_MODULE_FUNCTION
#define GPIO_PORT_ACLK GPIO_PORT_P1
#define GPIO_PIN_ACLK GPIO_PIN1
#define GPIO_FUNCTION_ACLK GPIO_SECONDARY_MODULE_FUNCTION
#define GPIO_PORT_UCA0TXD GPIO_PORT_P1
#define GPIO_PIN_UCA0TXD GPIO_PIN7
#define GPIO_FUNCTION_UCA0TXD GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCA0RXD GPIO_PORT_P1
#define GPIO_PIN_UCA0RXD GPIO_PIN6
#define GPIO_FUNCTION_UCA0RXD GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCB0SCL GPIO_PORT_P1
#define GPIO_PIN_UCB0SCL GPIO_PIN3
#define GPIO_FUNCTION_UCB0SCL GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCB0SDA GPIO_PORT_P1
#define GPIO_PIN_UCB0SDA GPIO_PIN2
#define GPIO_FUNCTION_UCB0SDA GPIO_PRIMARY_MODULE_FUNCTION
#endif // __MSP430FR2311__
#ifdef __MSP430FR2433__
#define GPIO_PORT_LED1 GPIO_PORT_P1
#define GPIO_PIN_LED1 GPIO_PIN0
#define GPIO_PORT_LED2 GPIO_PORT_P1
#define GPIO_PIN_LED2 GPIO_PIN1
#define GPIO_PORT_S1 GPIO_PORT_P2
#define GPIO_PIN_S1 GPIO_PIN3
#define GPIO_PORT_S2 GPIO_PORT_P2
#define GPIO_PIN_S2 GPIO_PIN7
#define GPIO_PORT_ADC7 GPIO_PORT_P1
#define GPIO_PIN_ADC7 GPIO_PIN7
#define GPIO_FUNCTION_ADC7 GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_MCLK GPIO_PORT_P1
#define GPIO_PIN_MCLK GPIO_PIN3
#define GPIO_FUNCTION_MCLK GPIO_SECONDARY_MODULE_FUNCTION
#define GPIO_PORT_SMCLK GPIO_PORT_P1
#define GPIO_PIN_SMCLK GPIO_PIN7
#define GPIO_FUNCTION_SMCLK GPIO_SECONDARY_MODULE_FUNCTION
#define GPIO_PORT_ACLK GPIO_PORT_P2
#define GPIO_PIN_ACLK GPIO_PIN2
#define GPIO_FUNCTION_ACLK GPIO_SECONDARY_MODULE_FUNCTION
#define GPIO_PORT_UCA0TXD GPIO_PORT_P1
#define GPIO_PIN_UCA0TXD GPIO_PIN4
#define GPIO_FUNCTION_UCA0TXD GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCA0RXD GPIO_PORT_P1
#define GPIO_PIN_UCA0RXD GPIO_PIN5
#define GPIO_FUNCTION_UCA0RXD GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCB0SCL GPIO_PORT_P1
#define GPIO_PIN_UCB0SCL GPIO_PIN3
#define GPIO_FUNCTION_UCB0SCL GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCB0SDA GPIO_PORT_P1
#define GPIO_PIN_UCB0SDA GPIO_PIN2
#define GPIO_FUNCTION_UCB0SDA GPIO_PRIMARY_MODULE_FUNCTION
#endif // __MSP430FR2433__
#ifdef __MSP430FR2355__
#define GPIO_PORT_LED1 GPIO_PORT_P1
#define GPIO_PIN_LED1 GPIO_PIN0
#define GPIO_PORT_LED2 GPIO_PORT_P6
#define GPIO_PIN_LED2 GPIO_PIN6
#define GPIO_PORT_S1 GPIO_PORT_P4
#define GPIO_PIN_S1 GPIO_PIN1
#define GPIO_PORT_S2 GPIO_PORT_P2
#define GPIO_PIN_S2 GPIO_PIN3
#define GPIO_PORT_ADC7 GPIO_PORT_P1
#define GPIO_PIN_ADC7 GPIO_PIN7
#define GPIO_FUNCTION_ADC7 GPIO_TERNARY_MODULE_FUNCTION
#define GPIO_PORT_XIN GPIO_PORT_P2
#define GPIO_PIN_XIN GPIO_PIN_P7
#define GPIO_FUNCTION_XIN GPIO_SECONDARY_MODULE_FUNCTION
#define GPIO_PORT_XOUT GPIO_PORT_P2
#define GPIO_PIN_XOUT GPIO_PIN_P6
#define GPIO_FUNCTION_XOUT GPIO_SECONDARY_MODULE_FUNCTION
#define GPIO_PORT_MCLK GPIO_PORT_P3
#define GPIO_PIN_MCLK GPIO_PIN0
#define GPIO_FUNCTION_MCLK GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_SMCLK GPIO_PORT_P3
#define GPIO_PIN_SMCLK GPIO_PIN4
#define GPIO_FUNCTION_SMCLK GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_ACLK GPIO_PORT_P1
#define GPIO_PIN_ACLK GPIO_PIN1
#define GPIO_FUNCTION_ACLK GPIO_SECONDARY_MODULE_FUNCTION
#define GPIO_PORT_UCA0TXD GPIO_PORT_P1
#define GPIO_PIN_UCA0TXD GPIO_PIN7
#define GPIO_FUNCTION_UCA0TXD GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCA0RXD GPIO_PORT_P1
#define GPIO_PIN_UCA0RXD GPIO_PIN6
#define GPIO_FUNCTION_UCA0RXD GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCB0SCL GPIO_PORT_P1
#define GPIO_PIN_UCB0SCL GPIO_PIN3
#define GPIO_FUNCTION_UCB0SCL GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_UCB0SDA GPIO_PORT_P1
#define GPIO_PIN_UCB0SDA GPIO_PIN2
#define GPIO_FUNCTION_UCB0SDA GPIO_PRIMARY_MODULE_FUNCTION
#define GPIO_PORT_SACOA0O GPIO_PORT_P1
#define GPIO_PIN_SACOA0O GPIO_PIN1
#define GPIO_FUNCTION_SACOA0O GPIO_TERNARY_MODULE_FUNCTION
#define GPIO_PORT_SACOA0N GPIO_PORT_P1
#define GPIO_PIN_SACOA0N GPIO_PIN2
#define GPIO_FUNCTION_SACOA0N GPIO_TERNARY_MODULE_FUNCTION
#define GPIO_PORT_SACOA0P GPIO_PORT_P1
#define GPIO_PIN_SACOA0P GPIO_PIN3
#define GPIO_FUNCTION_SACOA0P GPIO_TERNARY_MODULE_FUNCTION
#define GPIO_PORT_SACOA2O GPIO_PORT_P3
#define GPIO_PIN_SACOA2O GPIO_PIN1
#define GPIO_FUNCTION_SACOA2O GPIO_TERNARY_MODULE_FUNCTION
#define GPIO_PORT_SACOA2N GPIO_PORT_P3
#define GPIO_PIN_SACOA2N GPIO_PIN2
#define GPIO_FUNCTION_SACOA2N GPIO_TERNARY_MODULE_FUNCTION
#define GPIO_PORT_SACOA2P GPIO_PORT_P3
#define GPIO_PIN_SACOA2P GPIO_PIN3
#define GPIO_FUNCTION_SACOA2P GPIO_TERNARY_MODULE_FUNCTION
#define GPIO_PORT_COMP0O GPIO_PORT_P2
#define GPIO_PIN_COMP0O GPIO_PIN0
#define GPIO_FUNCTION_COMP0O GPIO_SECONDARY_MODULE_FUNCTION
#endif // __MSP430FR2355__
#endif // __BOARD_H__

View File

@ -119,11 +119,6 @@
"command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc",
"file" : "/home/frederik/workspace_ccstheia/ESR-11/jsmn/jsmn.c"
},
{
"directory" : "/home/frederik/workspace_ccstheia/ESR-11/Debug",
"command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc",
"file" : "/home/frederik/workspace_ccstheia/ESR-11/main.c"
},
{
"directory" : "/home/frederik/workspace_ccstheia/ESR-11/Debug",
"command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc",
@ -132,11 +127,21 @@
{
"directory" : "/home/frederik/workspace_ccstheia/ESR-11/Debug",
"command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc",
"file" : "/home/frederik/workspace_ccstheia/ESR-11/i2c_lcd.c"
"file" : "/home/frederik/workspace_ccstheia/ESR-11/main.c"
},
{
"directory" : "/home/frederik/workspace_ccstheia/ESR-11/Debug",
"command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc",
"file" : "/home/frederik/workspace_ccstheia/ESR-11/morse.c"
},
{
"directory" : "/home/frederik/workspace_ccstheia/ESR-11/Debug",
"command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc",
"file" : "/home/frederik/workspace_ccstheia/ESR-11/i2c.c"
},
{
"directory" : "/home/frederik/workspace_ccstheia/ESR-11/Debug",
"command" : "clang++ -I\"/home/frederik/.ti/ccs2010/ccs/ccs_base/msp430/include\" -I\"/home/frederik/workspace_ccstheia/ESR-11\" -I\"/home/frederik/workspace_ccstheia/ESR-11/jsmn\" -I\"/home/frederik/workspace_ccstheia/ESR-11/driverlib/MSP430FR2xx_4xx\" -I\"/home/frederik/.ti/ccs2010/ccs/tools/compiler/ti-cgt-msp430_21.6.1.LTS/include\" -D__MSP430FR2355__ -D_FRWP_ENABLE -D_INFO_FRWP_ENABLE -xc",
"file" : "/home/frederik/workspace_ccstheia/ESR-11/lcd.c"
}
]

View File

@ -1,6 +1,18 @@
/* ========================================================================== */
/* constants.h */
/* ========================================================================== */
/**
* @file constants.h
* @brief Reused constants not included in the std-Headers.
* @brief Projektweite Konstanten
* @author Frederik Beimgraben
* @author Minh Dan Cam
* @author Luis Meyer
* @date 02.07.2025
*/
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define NULL 0
#endif /* CONSTANTS_H */

149
i2c.c Normal file
View File

@ -0,0 +1,149 @@
/* ========================================================================== */
/* I2C.c */
/* ========================================================================== */
/**
* @file I2C.c
* @author wehrberger
* @date 31.05.2025
*
* @brief Implementierung eines minimalen blockierenden I²C-Master-Treibers.
*/
#include "i2c.h"
#include "msp430fr2355.h"
#include <stdint.h>
#include <stdbool.h>
/** Pointer auf das aktuell zu übertragende Byte. */
static char *packet;
/** Index des nächsten zu übertragenden Bytes. */
static unsigned int dataCount;
/** Anzahl der Bytes in @ref packet. */
static unsigned int packetLength;
/** Speicher für das zuletzt vom ISR empfangene Byte. */
static char dataIn;
static volatile bool i2cDone = false;
void I2C_init(void)
{
// USCI in Reset setzen um Konfiguration zu ermöglichen
UCB0CTLW0 |= UCSWRST;
// SMCLK wählen und durch 20 teilen → 50 kHz SCL
UCB0CTLW0 |= UCSSEL_3;
UCB0BRW = 20;
// I²C Master, 7-Bit Adressierung
UCB0CTLW0 |= UCMODE_3 | UCMST;
// Automatischer STOP nach Byte-Zähler (UCB0TBCNT) erreicht Null
UCB0CTLW1 |= UCASTP_2;
// Port-Mapping: P1.2 = SDA, P1.3 = SCL
P1SEL1 &= ~(BIT2 | BIT3);
P1SEL0 |= BIT2 | BIT3;
// Modul aktivieren
UCB0CTLW0 &= ~UCSWRST;
// Interrupts: RX, TX, STOP, NACK
UCB0IE |= UCRXIE0 | UCTXIE0 | UCSTPIE | UCNACKIE;
__enable_interrupt();
}
void I2C_write(uint8_t slaveAddress, char data[], uint8_t length)
{
UCB0I2CSA = slaveAddress;
packet = data;
packetLength = length;
dataCount = 0;
// Master-Transmit-Modus
UCB0CTLW0 |= UCTR;
UCB0TBCNT = length;
// START generieren, dann schlafen bis STOP
UCB0CTLW0 |= UCTXSTT;
i2cDone = false;
while (!i2cDone)
{
LPM3; // Warten auf STOP → ISR weckt uns auf
}
}
char I2C_read_reg(uint8_t slaveAddress, uint8_t registerAddress)
{
// Registeradresse zuerst senden
char addressBuffer[1] = {registerAddress};
I2C_write(slaveAddress, addressBuffer, 1);
// In Empfangsmodus wechseln und 1 Byte anfordern
UCB0CTLW0 &= ~UCTR;
UCB0TBCNT = 1;
UCB0CTLW0 |= UCTXSTT; // Repeated START
i2cDone = false;
while (!i2cDone)
{
LPM3; // Warten auf STOP → ISR weckt uns auf
}
return dataIn;
}
/* ========================================================================== */
/* Interrupt Service Routine */
/* ========================================================================== */
/**
* @brief Vereinheitlichte ISR für alle USCI_B0 I²C-Ereignisse.
*
* Nur vier Interrupt-Ursachen werden derzeit behandelt:
* - UCNACKIFG : Kennzeichnet fehlendes ACK (nur Debug-Hook)
* - UCSTPIFG : STOP erkannt LPM3 verlassen
* - UCRXIFG0 : Ein Byte empfangen
* - UCTXIFG0 : Sendepuffer bereit für nächstes Byte
*
* Alle anderen Ursachen fallen durch zum default.
*/
#pragma vector = EUSCI_B0_VECTOR
__interrupt void EUSCI_B0_I2C_ISR(void)
{
switch (__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
{
case USCI_I2C_UCNACKIFG:
// NACK → CPU aufwecken (LPM3 verlassen)
i2cDone = true;
__bic_SR_register_on_exit(LPM3_bits);
break;
case USCI_I2C_UCSTPIFG:
// STOP → CPU aufwecken (LPM3 verlassen)
i2cDone = true;
__bic_SR_register_on_exit(LPM3_bits);
break;
case USCI_I2C_UCRXIFG0:
// Empfangenes Byte speichern
dataIn = UCB0RXBUF;
break;
case USCI_I2C_UCTXIFG0:
// Nächstes Datenbyte senden oder Übertragung beenden
UCB0TXBUF = packet[dataCount++];
if (dataCount >= packetLength)
dataCount = 0; // Für nächste Transaktion zurücksetzen
break;
default:
// Unbehandelter Vektor nichts zu tun
break;
}
}

44
i2c.h Normal file
View File

@ -0,0 +1,44 @@
/* ========================================================================== */
/* I2C.h */
/* ========================================================================== */
/**
* @file I2C.h
* @author wehrberger
* @date 31.05.2025
*
* @brief Schnittstelle für einen minimalen blockierenden I²C-Master-Treiber.
*/
#ifndef I2C_H
#define I2C_H
#include <stdint.h>
#include <stdbool.h>
/**
* @brief Initialisiert das I²C-Modul als Master (SMCLK/20 50 kHz).
*/
void I2C_init(void);
/**
* @brief Sendet ein Datenpacket an einen I²C-Slave.
*
* @param slaveAddress 7-Bit I²C-Adresse des Zielgeräts.
* @param data Zeiger auf zu sendende Bytes.
* @param length Anzahl der zu sendenden Bytes.
*/
void I2C_write(uint8_t slaveAddress, char data[], uint8_t length);
/**
* @brief Liest ein einzelnes Byte aus einem Register eines I²C-Slaves.
*
* Führt zunächst einen Schreibvorgang durch, um die Registeradresse zu senden,
* und liest dann per Repeated START ein Byte zurück.
*
* @param slaveAddress 7-Bit I²C-Adresse des Zielgeräts.
* @param registerAddress Adresse des auszulesenden Registers.
* @return Das gelesene Byte.
*/
char I2C_read_reg(uint8_t slaveAddress, uint8_t registerAddress);
#endif /* I2C_H */

132
i2c_lcd.c
View File

@ -1,132 +0,0 @@
#include "i2c_lcd.h"
#include <driverlib.h>
#include <msp430.h>
/* Adjust to your modules I²C address (often 0x27 or 0x3F) */
#define LCD_I2C_ADDR 0x27
/* PCF8574 pin ↔ LCD pin mapping (change if your backpack is different) */
#define P_RS 0x01 /* P0 → RS */
#define P_RW 0x02 /* P1 → RW */
#define P_EN 0x04 /* P2 → E */
#define P_BL 0x08 /* P3 → Backlight */
#define DATA_MASK 0xF0
/** spin until BUS not busy, or timeoutCycles hits zero */
static bool waitI2CBusyClear(uint32_t timeoutCycles)
{
/* keep looping while the BUSY bit remains set */
while ((EUSCI_B_I2C_isBusBusy(EUSCI_B0_BASE) == EUSCI_B_I2C_BUS_BUSY)
&& --timeoutCycles)
;
return (timeoutCycles != 0);
}
static void i2cWriteByte(uint8_t b)
{
/* make sure bus is free */
if (!waitI2CBusyClear(50000)) return;
/* generate START + send first byte */
EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, b);
/* wait until the byte is actually out and bus goes busy→idle */
if (!waitI2CBusyClear(50000)) return;
/* STOP to free the bus again */
EUSCI_B_I2C_masterSendMultiByteStop(EUSCI_B0_BASE);
/* optional small delay for the expander to settle */
__delay_cycles(50);
}
static void pulse(uint8_t data)
{
i2cWriteByte(data | P_EN);
__delay_cycles(200);
i2cWriteByte(data & ~P_EN);
__delay_cycles(200);
}
/* send upper or lower nibble with control bits */
static void write4(uint8_t nibble, uint8_t control)
{
uint8_t out = (nibble << 4) & DATA_MASK;
out |= control | P_BL;
i2cWriteByte(out);
pulse(out);
}
static void send(uint8_t value, uint8_t mode)
{
write4(value >> 4, mode);
write4(value & 0x0F, mode);
}
/** Commands (mode = 0), data (mode = P_RS) */
static inline void cmd(uint8_t c) { send(c, 0); }
static inline void data(uint8_t d){ send(d, P_RS); }
void lcdInit(void)
{
/* 1) Init the MSP I²C peripheral on B0 (P1.6=SCL, P1.7=SDA) */
GPIO_setAsPeripheralModuleFunctionInputPin(
GPIO_PORT_P1,
GPIO_PIN6 | GPIO_PIN7,
GPIO_PRIMARY_MODULE_FUNCTION
);
EUSCI_B_I2C_initMasterParam i2cCfg = {
.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK,
.i2cClk = CS_getSMCLK(),
.dataRate = EUSCI_B_I2C_SET_DATA_RATE_100KBPS,
.byteCounterThreshold = 1,
.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP,
};
EUSCI_B_I2C_initMaster(EUSCI_B0_BASE, &i2cCfg);
EUSCI_B_I2C_setSlaveAddress(EUSCI_B0_BASE, LCD_I2C_ADDR);
EUSCI_B_I2C_enable(EUSCI_B0_BASE);
__delay_cycles(50000);
/* 4-bit init sequence */
write4(0x03, 0);
__delay_cycles(50000);
write4(0x03, 0);
__delay_cycles(50000);
write4(0x03, 0);
__delay_cycles(50000);
write4(0x02, 0);
__delay_cycles(50000);
/* function set: 2-line, 5×8 dots */
cmd(0x28);
/* display off */
cmd(0x08);
/* clear */
cmd(0x01);
__delay_cycles(20000);
/* entry mode: cursor moves right */
cmd(0x06);
/* display on, cursor off, blink off */
cmd(0x0C);
}
void lcdPrint(const char *str)
{
while (*str) {
data((uint8_t)*str++);
}
}
void lcdPutChar(char c)
{
data((uint8_t)c);
}
void lcdSetCursor(uint8_t row, uint8_t col)
{
/* DDRAM addresses: 0x00 + col for row0, 0x40 + col for row1 */
uint8_t addr = (row == 0 ? 0x00 : 0x40) + col;
cmd(0x80 | addr);
}

View File

@ -1,18 +0,0 @@
#ifndef I2C_LCD_H
#define I2C_LCD_H
#include <stdint.h>
/** Call once at startup to power up the I²C bus and init the LCD controller. */
void lcdInit(void);
/** Print a NUL-terminated string at the current cursor position. */
void lcdPrint(const char *str);
/** Send a single character. */
void lcdPutChar(char c);
/** Move the cursor to (row, col), 0-based. */
void lcdSetCursor(uint8_t row, uint8_t col);
#endif // I2C_LCD_H

View File

@ -39,12 +39,12 @@ static const char keys[ROWS][COLS] = {
/** Row port and pin definitions */
static const uint8_t rowPort[ROWS] = { GPIO_PORT_P6, GPIO_PORT_P6, GPIO_PORT_P6, GPIO_PORT_P6 };
static const uint16_t rowPin [ROWS] = { GPIO_PIN1, GPIO_PIN2, GPIO_PIN3, GPIO_PIN4 };
static const uint16_t rowPin [ROWS] = { GPIO_PIN0, GPIO_PIN1, GPIO_PIN2, GPIO_PIN3 };
/** Column port and pin definitions */
enum { COL0 = 0, COL1, COL2, COL3 };
static const uint8_t colPort[COLS] = { GPIO_PORT_P3, GPIO_PORT_P2, GPIO_PORT_P3, GPIO_PORT_P3 };
static const uint16_t colPin [COLS] = { GPIO_PIN7, GPIO_PIN4, GPIO_PIN3, GPIO_PIN2 };
static const uint8_t colPort[COLS] = { GPIO_PORT_P3, GPIO_PORT_P1, GPIO_PORT_P3, GPIO_PORT_P1 };
static const uint16_t colPin [COLS] = { GPIO_PIN0, GPIO_PIN1, GPIO_PIN2, GPIO_PIN4 };
/** User callback invoked on confirmed key press */
static KeypadCallback_t keyCallback = NULL;
@ -130,15 +130,23 @@ static void handleColumnInterrupt(uint8_t colIdx)
/**
* @brief Interrupt Service Routine for PORT2 (handles COL1 on P2.4)
*/
#pragma vector=PORT2_VECTOR
__interrupt void PORT2_ISR(void)
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
uint16_t status = GPIO_getInterruptStatus(GPIO_PORT_P2, colPin[COL1]);
uint16_t mask = colPin[COL1] | colPin[COL3];
uint16_t status = GPIO_getInterruptStatus(GPIO_PORT_P1, mask);
if (status & colPin[COL1]) {
handleColumnInterrupt(COL1);
GPIO_clearInterrupt(GPIO_PORT_P2, colPin[COL1]);
__bic_SR_register_on_exit(LPM0_bits);
}
if (status & colPin[COL3]) {
handleColumnInterrupt(COL3);
__bic_SR_register_on_exit(LPM0_bits);
}
GPIO_clearInterrupt(GPIO_PORT_P2, colPin[COL1]);
}
/**
@ -154,14 +162,12 @@ __interrupt void PORT3_ISR(void)
handleColumnInterrupt(COL0);
__bic_SR_register_on_exit(LPM0_bits);
}
if (status & colPin[COL2]) {
handleColumnInterrupt(COL2);
__bic_SR_register_on_exit(LPM0_bits);
}
if (status & colPin[COL3]) {
handleColumnInterrupt(COL3);
__bic_SR_register_on_exit(LPM0_bits);
}
GPIO_clearInterrupt(GPIO_PORT_P3, mask);
}

86
lcd.c Normal file
View File

@ -0,0 +1,86 @@
#include "lcd.h"
#include "i2c.h" /* Ihr I²C-Master-Treiber */
#include <msp430fr2355.h> /* für __delay_cycles() */
#include <stdint.h>
/* --- Interne Helfer: sendet eine 4-Bit-Halbnibble plus Control-Bits --- */
static void lcd_write_nibble(uint8_t nibble, uint8_t control)
{
char buf[1];
/* High-Nibble in die oberen 4 Bits */
buf[0] = (nibble << 4) | control | LCD_BACKLIGHT;
/* EN=1 */
I2C_write(LCD_I2C_ADDR, buf, 1);
buf[0] |= LCD_ENABLE;
I2C_write(LCD_I2C_ADDR, buf, 1);
__delay_cycles(500); /* ca. 50 µs @ 1 MHz */
/* EN=0 */
buf[0] &= ~LCD_ENABLE;
I2C_write(LCD_I2C_ADDR, buf, 1);
__delay_cycles(500);
}
/* Sendet ein volles Byte (2×4-Bit) als Befehl (RS=0) */
static void lcd_send_cmd(uint8_t cmd)
{
lcd_write_nibble(cmd >> 4, 0x00);
lcd_write_nibble(cmd & 0x0F, 0x00);
}
/* Sendet ein volles Byte als Daten (RS=1) */
static void lcd_send_data(uint8_t data)
{
lcd_write_nibble(data >> 4, LCD_RS);
lcd_write_nibble(data & 0x0F, LCD_RS);
}
void lcd_init(void)
{
/* Wartezeit nach Power-Up */
__delay_cycles(50000); /* ca. 50 ms */
/* Initial­sequenz 8-Bit-Befehle (3×) */
lcd_write_nibble(0x03, 0x00);
__delay_cycles(20000);
lcd_write_nibble(0x03, 0x00);
__delay_cycles(5000);
lcd_write_nibble(0x03, 0x00);
__delay_cycles(2000);
/* In 4-Bit-Modus schalten */
lcd_write_nibble(0x02, 0x00);
__delay_cycles(2000);
/* Funktion: 4-Bit, 2 Zeilen, 5×8 Punkte */
lcd_send_cmd(0x28);
/* Display off */
lcd_send_cmd(0x08);
/* Clear */
lcd_send_cmd(0x01);
__delay_cycles(2000);
/* Entry mode: Cursor++ */
lcd_send_cmd(0x06);
/* Display on, Cursor off, Blink off */
lcd_send_cmd(0x0C);
}
void lcd_clear(void)
{
lcd_send_cmd(0x01);
__delay_cycles(2000);
}
void lcd_set_cursor(uint8_t row, uint8_t col)
{
uint8_t addr = (row == 0 ? 0x00 : 0x40) + (col & 0x0F);
lcd_send_cmd(0x80 | addr);
}
void lcd_print(const char *str)
{
while (*str)
{
lcd_send_data((uint8_t)*str++);
}
}

35
lcd.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef LCD_I2C_H
#define LCD_I2C_H
#include <stdint.h>
/* PCF8574 I²C-Expander Adresse */
#define LCD_I2C_ADDR 0x27
/* PCF8574 P-Pins → LCD Control */
#define LCD_BACKLIGHT 0x08
#define LCD_ENABLE 0x04
#define LCD_RW 0x02
#define LCD_RS 0x01
/**
* @brief Initialisiert das LCD (4-Bit-Modus, 2 Zeilen, 5×8 Punkte).
*/
void lcd_init(void);
/**
* @brief Löscht das Display und setzt Cursor auf Home.
*/
void lcd_clear(void);
/**
* @brief Setzt den Cursor auf (row, col). Zero-based: row=0..1, col=0..15.
*/
void lcd_set_cursor(uint8_t row, uint8_t col);
/**
* @brief Schreibt einen C-String ins Display an der aktuellen Cursor-Position.
*/
void lcd_print(const char *str);
#endif /* LCD_I2C_H */

158
main.c
View File

@ -15,72 +15,13 @@
#include <stdbool.h>
#include "keypad.h"
#include "morse.h"
/** UART port/pin definitions */
#define UART_TX_PORT GPIO_PORT_P1 /** UART TX port */
#define UART_TX_PIN GPIO_PIN2 /** UART TX pin */
#define UART_RX_PORT GPIO_PORT_P1 /** UART RX port */
#define UART_RX_PIN GPIO_PIN3 /**< UART RX pin */
/** UART baudrate configuration for 9600 @ 1MHz SMCLK */
#define BAUDRATE_PRESCL 6U /**< UCBR */
#define BAUDRATE_FIRSTM 8U /**< UCBRF */
#define BAUDRATE_SECONDM 0U /**< UCBRS */
#include "i2c.h"
#include "Board.h"
/** On-board LED port and pin (used by Morse module) */
#define LED_PORT GPIO_PORT_P1 /**< On-board LED port */
#define LED_PIN GPIO_PIN0 /**< On-board LED pin */
/** Shared buffer for last key press and ready flag (set in ISR) */
volatile char g_lastKey = 0; /**< Last key pressed */
volatile bool g_keyReady = false; /**< Flag indicating key available */
/**
* @brief Initialize UART module for console output at 9600 baud.
*/
static void initSerial(void)
{
EUSCI_A_UART_initParam uartCfg;
/* Configure TX/RX pins for UART function */
GPIO_setAsPeripheralModuleFunctionInputPin(
UART_TX_PORT | UART_RX_PORT,
UART_TX_PIN | UART_RX_PIN,
GPIO_PRIMARY_MODULE_FUNCTION
);
/* Populate UART configuration structure */
uartCfg.selectClockSource = EUSCI_A_UART_CLOCKSOURCE_SMCLK;
uartCfg.clockPrescalar = BAUDRATE_PRESCL;
uartCfg.firstModReg = BAUDRATE_FIRSTM;
uartCfg.secondModReg = BAUDRATE_SECONDM;
uartCfg.parity = EUSCI_A_UART_NO_PARITY;
uartCfg.msborLsbFirst = EUSCI_A_UART_LSB_FIRST;
uartCfg.numberofStopBits = EUSCI_A_UART_ONE_STOP_BIT;
uartCfg.uartMode = EUSCI_A_UART_MODE;
uartCfg.overSampling = EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;
/* Apply configuration and enable UART */
EUSCI_A_UART_init(EUSCI_A0_BASE, &uartCfg);
EUSCI_A_UART_enable(EUSCI_A0_BASE);
}
/**
* @brief Transmit a null-terminated string over UART.
* @param s Pointer to string to send
*/
static void serialPrint(const char *s)
{
const char *ptr = s;
while (*ptr) {
/* Send next character */
EUSCI_A_UART_transmitData(EUSCI_A0_BASE, *ptr++);
/* Wait until transmission completes */
while (EUSCI_A_UART_queryStatusFlags(
EUSCI_A0_BASE, EUSCI_A_UART_BUSY));
}
}
/**
* @brief Keypad callback invoked on key press interrupt.
* @param key ASCII character of pressed key
@ -89,11 +30,55 @@ static void serialPrint(const char *s)
*/
static void myKeyHandler(char key)
{
g_lastKey = key;
g_keyReady = true;
blinkMorseChar(key);
}
void init_timer(void) {
static Timer_B_initUpModeParam param = {0};
param.clockSource = TIMER_B_CLOCKSOURCE_SMCLK;
param.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_1;
param.timerPeriod = 999; // wenn 1000 Taktimpulse gezählt
// wurden, erfolgt ein Interrupt
// Periodendauer somit 1ms
param.timerInterruptEnable_TBIE =
TIMER_B_TBIE_INTERRUPT_DISABLE; // no interrupt on 0x0000
param.captureCompareInterruptEnable_CCR0_CCIE =
TIMER_B_CAPTURECOMPARE_INTERRUPT_ENABLE; // interrupt on TRmax
param.timerClear = TIMER_B_DO_CLEAR;
param.startTimer = true;
// start Timer:
Timer_B_initUpMode(TB0_BASE, &param);
}
void init_i2c(void) {
EUSCI_B_I2C_initMasterParam param = {0};
// Configure Pins for I2C
/*
* Select Port 1
* Set Pin 2, 3 to input with function, (UCB0SIMO/UCB0SDA, UCB0SOMI/UCB0SCL).
*/
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_UCB0SCL, GPIO_PIN_UCB0SCL, GPIO_FUNCTION_UCB0SCL);
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_UCB0SDA, GPIO_PIN_UCB0SDA, GPIO_FUNCTION_UCB0SDA);
param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
param.i2cClk = CS_getSMCLK();
param.dataRate = EUSCI_B_I2C_SET_DATA_RATE_100KBPS;
param.byteCounterThreshold = 1;
param.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP;
EUSCI_B_I2C_initMaster(EUSCI_B0_BASE, &param);
//Specify slave address
EUSCI_B_I2C_setSlaveAddress(EUSCI_B0_BASE, 0x27);
//Set in transmit mode
EUSCI_B_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
//Enable I2C Module to start operations
EUSCI_B_I2C_enable(EUSCI_B0_BASE);
}
/**
* @brief Main application entry point.
*
@ -104,9 +89,6 @@ static void myKeyHandler(char key)
*/
int main(void)
{
char buf[32];
int len;
/* Stop watchdog and unlock GPIO pins */
WDT_A_hold(WDT_A_BASE);
PMM_unlockLPM5();
@ -115,27 +97,43 @@ int main(void)
GPIO_setAsOutputPin(LED_PORT, LED_PIN);
GPIO_setOutputLowOnPin(LED_PORT, LED_PIN);
/* Initialize UART console */
initSerial();
serialPrint("Keypad + LED test starting...\r\n");
/* Initialize keypad interrupt driver */
initKeypadInterrupts(myKeyHandler);
init_timer();
I2C_init(); /* I²C-Master initialisieren */
lcd_init(); /* LCD initialisieren */
lcd_set_cursor(0, 0);
lcd_print("Hello, world!");
lcd_set_cursor(1, 0);
lcd_print("MSP430 + I2C");
/* Enter low-power mode and wait for key interrupts */
for (;;) {
__bis_SR_register(LPM0_bits | GIE); /* Enter LPM0 with interrupts enabled */
__no_operation();
if (g_keyReady) {
/* Echo key over UART */
len = sprintf(buf, "Key pressed: %c\r\n", g_lastKey);
(void)len;
serialPrint(buf);
g_keyReady = false;
/* Do nothing */
}
}
/* Should never reach here */
return 0;
}
/**
* @brief Führt eine blockierende Wartezeit aus.
* @param ms Zeit in Millisekunden
*/
void sleep(uint16_t ms) {
while (ms--) {
__bis_SR_register(LPM0_bits + GIE);
__no_operation();
}
}
// TimerB0 Interrupt Vector (TBxIV) handler
#pragma vector=TIMER0_B0_VECTOR
__interrupt void TIMER0_B0_ISR(void)
{
__bic_SR_register_on_exit(LPM0_bits);
}