XMC4700 Relax Kit

Das XMC4700 Relax Kit von Infineon ist ein leistungsstarkes Entwicklungsboard, das auf dem XMC4700-Mikrocontroller basiert. Dieser Mikrocontroller gehört zur XMC4000-Serie und ist für anspruchsvolle Industrieanwendungen konzipiert. Das Board bietet eine Vielzahl an Schnittstellen, darunter Ethernet, CAN, USB und SPI, was es ideal für Anwendungen in der Automatisierungstechnik, Motorsteuerung und dem industriellen IoT (IIoT) macht.

Table of Contents

Aufbau

Das Board ist wie folgt aufgebaut: Es besitzt den XMC4700-F144K2048 Mikrocontroller, einen ARM® Cortex®-M4 mit 144 MHz, 2 MB Flash und 352 KB RAM. Die Stromversorgung kann über USB oder eine externe Quelle mit integriertem Spannungsregler erfolgen. Für die Kommunikation stehen Ethernet (RJ45), CAN, USB, UART, SPI und I²C zur Verfügung. Ein integrierter SEGGER J-Link Lite Debugger ermöglicht unkompliziertes Programmieren und Debuggen. Zudem gibt es Arduino-kompatible Header und PMOD-Steckplätze zur Erweiterung. Ergänzt wird die Ausstattung durch LEDs, Taster und einen Micro-SD-Kartensteckplatz.

Quelle: XMC4700 XMC4800 User Manual

Das Blockschaltbild und weitere Infos findet man im User Manual.

Quelle: XMC4700 XMC4800 User Manual

Hier ist eine weitere Ansicht des XMC4700 Relax Kits.

Quelle: XMC4700 XMC4800 Reference Manual

CPU & System

  • ARM Cortex-M4: Prozessor mit DSP-Unterstützung für Echtzeit-Anwendungen.
  • System, DCode, ICode: Busse für Speicherzugriffe (Instruktionen & Daten).

Bus-Struktur

  • Bus Matrix: Vermittelt Daten zwischen CPU, Speicher und Peripheriegeräten.
  • PBA0/PBA1: Peripherie-Bus-Adapter zur Verbindung von Peripherieeinheiten mit dem Hauptbus.

Speicher

  • PMU ROM & Flash: Persistenter Speicher für Firmware und Konfiguration.
  • PSRAM: Pseudo-Static RAM (flüchtiger Arbeitsspeicher).
  • DSRAM1/DSRAM2: Data SRAM, schneller RAM für Variablen und Zwischenspeicherung.
  • EBU (External Bus Unit): Schnittstelle für externe Speicher oder Peripherien.

DMA & Kommunikation

  • GPDMA0/GPDMA1 (General-Purpose DMA): Direkter Speicherzugriff für schnelle Datenübertragung ohne CPU-Last.
  • Ethernet: Netzwerkcontroller für LAN-Konnektivität.
  • USB OTG (On-The-Go): Unterstützt USB als Host oder Gerät.

Peripheriegeräte

  • USIC (Universal Serial Interface Controller 0, 1, 2): Konfigurierbare Schnittstelle für UART, SPI, I²C.
  • DSD (Delta-Sigma Demodulator): Digitale Signalverarbeitung für hochpräzise Messungen.
  • POSIF0/POSIF1 (Position Interface): Schnittstelle für Encoder zur Motorsteuerung.
  • CCU (Capture Compare Unit 40, 41, 42, 43, 80, 81): PWM- und Timereinheiten für Motorsteuerung.
  • LEDTS0 (LED and Touch-Sense Controller): Steuerung für LED-Displays & kapazitive Touch-Oberflächen.
  • PORTS: GPIO-Pins zur Steuerung externer Geräte.
  • DAC (Digital-Analog Converter): Wandelt digitale Signale in analoge Spannungen.
  • VADC (Voltage Analog-to-Digital Converter): ADC zur Wandlung von Sensorspannungen in digitale Werte.
  • SDMMC (Secure Digital MultiMediaCard Interface): Schnittstelle für SD-Karten.
  • MultiCAN: CAN-Bus-Schnittstelle für industrielle Netzwerke.

Systemsteuerung & Sicherheit

  • SCU (System Control Unit): Überwacht die Stromversorgung und Systemtakt.
  • RTC (Real-Time Clock): Echtzeituhr für Zeitstempel und Weckfunktionen.
  • ERU0/ERU1 (Event Request Unit): Ereignissteuerung für Interrupts.
  • WDT (Watchdog Timer): Schutzmechanismus gegen Systemabstürze.
  • FCE (Fast CRC Engine): Beschleunigte Berechnung von Prüfsummen (CRC).
  • EtherCAT: Industrie-Ethernet-Protokoll für Echtzeitsteuerung.

Ansteuerung verschiedener Bauteile

LM75A – Temperatursensor 

Der LM75A ist ein digitaler Temperatur-Sensor von Texas Instruments, der die Temperatur in einem Bereich von -55 °C bis +125 °C misst. Er kommuniziert über das I²C-Protokoll und liefert eine 9-Bit-Auflösung. Der Sensor verfügt über eine integrierte Temperaturkompensation und ermöglicht eine präzise Temperaturmessung mit einer Genauigkeit von ±2 °C.

Der Sensor wird über das I²C-Protokoll angesteuert, was eine einfache Integration in Mikrocontroller-basierte Systeme ermöglicht. Zur korrekten Ansteuerung und Konfiguration des Sensors ist es wichtig, in das Datenblatt von Texas Instruments zu schauen.

Wir benötigen mehrere wichtige Informationen, um den LM75A korrekt anzusteuern. Dazu gehört die Adresse des Sensors, die im I²C-Bus verwendet wird, sowie das Register, in dem die Temperaturdaten gespeichert sind. Des Weiteren ist es wichtig zu wissen, welche Daten der Sensor zurückgibt und wie diese korrekt interpretiert werden können, um präzise Temperaturmessungen zu erhalten.

In meinem Fall hat der Sensor die Adresse 0x48. Die Temperaturdaten sind im Register 0x00 gespeichert. Beim Auslesen erhalten wir 2 Bytes, von denen die ersten 7 Bits irrelevant sind. Die verbleibenden 9 Bits enthalten die Temperaturinformationen. Jedes Bit steht für eine Temperaturerhöhung von 0,5 Grad Celsius. Das bedeutet, dass eine Zahl von 50 in den 9 Bits eine Temperatur von +25 Grad Celsius darstellt.

Im I²C-Protokoll besteht die vollständige Adresse aus 8 Bit, wobei das letzte Bit (LSB) die Read/Write-Steuerung ist:

  • Bit 0 = 0 → Schreiboperation (Write)
  • Bit 0 = 1 → Leseoperation (Read)

Die 7-Bit-Adresse des LM75A ist 0x48. Damit die Adresse für das I²C-Protokoll in das 8-Bit-Format passt, wird sie um ein Bit nach links geschoben (<< 1), sodass Platz für das R/W-Bit entsteht

Um I²C korrekt zu verwenden, schauen wir in die entsprechende Deklaration der I²C-Bibliothek des XMC4700. Dort finden wir sowohl für den Transmit- als auch den Receive-Befehl die korrekte Anwendung.

Code Kopieren

I2C_MASTER_STATUS_t I2C_MASTER_Transmit(I2C_MASTER_t *handle, bool send_start, const uint32_t address,
                                        uint8_t *data, const uint32_t size, bool send_stop)
    
✅ Copied!
Code Kopieren

I2C_MASTER_STATUS_t I2C_MASTER_Receive(I2C_MASTER_t *handle, bool send_start, const uint32_t address, uint8_t * data,
                                   const uint32_t count, bool send_stop, bool send_nack)
    
✅ Copied!

Hier ein beispielhafter Code, wie man die 2 Bytes vom LM75A ausliest.

Code Kopieren

float readSensorLM75A() {
    uint8_t tempReg = 0x00;
    uint8_t DataStorage[2];
    uint8_t LM75 = 0x48 << 1;

    I2C_MASTER_Transmit(&I2C_MASTER_0, true, LM75, &tempReg, 1, false);
    while (I2C_MASTER_IsTxBusy(&I2C_MASTER_0));

    I2C_MASTER_Receive(&I2C_MASTER_0, true, LM75, DataStorage, 2, true, true);
    while (I2C_MASTER_IsRxBusy(&I2C_MASTER_0));

    return convertTemperature(DataStorage);
}
    
✅ Copied!

Hier ein Beispiel, um die empfangenen 16 Bit korrekt zu interpretieren:

Code Kopieren

float convertTemperature(unsigned char DataStorage[2]) {
    unsigned short tempBits = (DataStorage[0] << 1) | (DataStorage[1] >> 7);
    unsigned short temperatureValue = tempBits & 0xFF;

    if (temperatureValue == 0) {
        return 0.0;
    }

    return temperatureValue * 0.5;
}
    
✅ Copied!

Hier eine einfache main-Funktion, um die Daten auszulesen.

Code Kopieren

#include "DAVE.h"
#include <stdio.h>

volatile float temp;

void delay_ms(uint32_t ms) {
    for (uint32_t i = 0; i < (ms * 12000); i++);
}
    
✅ Copied!
Code Kopieren


int main(void)
{
    DAVE_STATUS_t status;

    status = DAVE_Init();

    if (status != DAVE_STATUS_SUCCESS)
    {
        XMC_DEBUG("DAVE APPs initialization failed\n");
        while (1U);
    }

    while (1U)
    {
        temp = readSensorLM75A();
        printf("Temperatur: %.2f°C\n", temp);
        delay_ms(1000);
    }

    return 0;
}
    
✅ Copied!

Das Vorgehen bei solchen Sensoren bleibt immer gleich: Zuerst das Datenblatt besorgen, die Adresse herausfinden und das gewünschte Register bestimmen. Danach werden die entsprechenden Daten empfangen und korrekt interpretiert. Zusätzlich könnte es erforderlich sein, dass das Bauteil zunächst noch initialisiert und/oder kalibriert werden muss.

HD44780 – LCD-Display

Das Display verfügt über einen I²C-Port-Expander, über den die Kommunikation mit dem Display erfolgt. Um diesen korrekt anzusteuern, orientieren wir uns am Datenblatt.

Zunächst ermitteln wir die I²C-Adresse des Expanders, da diese je nach Modell unterschiedlich sein kann. 

In meinem Fall betrug die Adresse 0x4E bzw. 0x27 mit einem Links-Shift um ein Bit.

 

Das Datenblatt gibt vor, wie die Kommunikation mit dem Gerät abläuft. Die Datenübertragung erfolgt in 4-Bit-Schritten: Vier Bits sind für die eigentlichen Daten vorgesehen, die anderen vier Bits dienen als Steuerleitungen. Die relevanten Steuerleitungen sind:

  • EN (Enable): Aktiviert die Datenübertragung.

  • R/W (Read/Write): Legt fest, ob gelesen oder geschrieben wird. Da das Display hauptsächlich beschrieben wird, bleibt dieser Wert in unserem Projekt konstant auf 0.

  • RS (Register Select): Bestimmt, ob die übermittelten Daten als Befehl oder als reine Anzeigedaten interpretiert werden.

Da die Übertragung in 4-Bit-Schritten erfolgt, müssen wir unsere 8-Bit-Daten in zwei sogenannte Nibbles aufteilen (jeweils 4 Bits Daten + 4 Bits Steuerleitungen). Ein Byte, das übertragen wird, setzt sich somit aus einem 4-Bit-Datenanteil und den Steuerbits zusammen.

 

Ein wichtiger Aspekt bei der Datenübertragung ist das EN-Bit, das für eine kurze Zeit aktiviert werden muss, damit die Daten korrekt übernommen werden. Der Ablauf sieht folgendermaßen aus:

  1. EN auf 0 setzen

  2. EN auf 1 setzen, um die Übertragung auszulösen

  3. EN wieder auf 0 setzen, um Fehler in späteren Übertragungen zu vermeiden

Auf dieser Basis erstellen wir unser I²C-Skript, das sowohl Daten als auch Befehle gemäß dem definierten Protokoll mit Nibbles und Steuerleitungen überträgt.

Um Kommunikationsprobleme zu vermeiden, die durch eine zu schnelle Datenübertragung an das Display entstehen könnten, implementieren wir eine Delay-Funktion mithilfe des SysTimers in DAVE.

Code Kopieren

TimerId = (uint32_t)SYSTIMER_CreateTimer(1000, SYSTIMER_MODE_ONE_SHOT, (void*)Delay_Interrupt, NULL);
bool Wait;

void Delay_Interrupt() 
{
    Wait = false;
}

void Delay(uint32_t time) 
{
    Wait = true;
    SYSTIMER_RestartTimer(TimerId, time * 1000);
    while (Wait == true);
}
    
✅ Copied!

Mit unserem Wissen aus dem vorherigen Sensor LM75A erstellen wir unsere gewünschte Funktion zur Steuerung des Displays. Dabei nutzen wir das gleiche Prinzip der I²C-Kommunikation, um Daten und Befehle korrekt zu übertragen.

Ein zusätzlicher Vorteil ist, dass wir auch die Hintergrundbeleuchtung (Backlight) des Displays steuern können. Dies geschieht über das vierte Bit vom LSB aus.

Code Kopieren

void SendByte(uint8_t address, uint8_t data) {
    uint8_t payload = data;
    I2C_MASTER_Transmit(&I2C_MASTER_0, true, address, &payload, 1, true);
    while (I2C_MASTER_IsTxBusy(&I2C_MASTER_0));
}

void SendNibble(uint8_t address, uint8_t data) {
    SendByte(address, data);        
    SendByte(address, data | 0x04); 
    SendByte(address, data);        
}

void SendData(uint8_t address, uint8_t data) {
    uint8_t highNibble = data & 0xF0;  
    uint8_t lowNibble  = (data << 4) & 0xF0; 

    SendNibble(address, highNibble | 0x09);  
    SendNibble(address, lowNibble  | 0x09);
}

void SendOrder(uint8_t address, uint8_t command) {
    uint8_t highNibble = command & 0xF0;  
    uint8_t lowNibble  = (command << 4) & 0xF0;

    SendNibble(address, highNibble | 0x08);  
    SendNibble(address, lowNibble  | 0x08);
}
    
✅ Copied!

Eine weitere wichtige Funktion ist das Schreiben von Zeichen auf das Display. Dabei senden wir dem Port-Expander die entsprechenden Daten, die auf dem Display angezeigt werden sollen.

Der Ablauf sieht folgendermaßen aus:

  • Die Zeichenkette wird zeichenweise verarbeitet.
  • Jedes Zeichen wird gemäß dem Nibble-Format (4 Bit + Steuerbits) gesendet.
  • Das RS-Bit wird auf 1 gesetzt, um anzuzeigen, dass es sich um Anzeigedaten handelt.
Code Kopieren

void Write(unsigned char* string1, unsigned char* string2)
{
    SendOrder(0x4E, 0x80);
    Delay(3); 

    size_t len1 = strlen((char*)string1);
    for (size_t i = 0; i < len1; i++)
    {
        SendData(0x4E, string1[i]); 
        Delay(2);  
    }

    SendOrder(0x4E, 0xC0);
    Delay(3); 

    size_t len2 = strlen((char*)string2);
    for (size_t i = 0; i < len2; i++)
    {
        SendData(0x4E, string2[i]); 
        Delay(2);  
    }
}
    
✅ Copied!

Bevor wir im 4-Bit-Modus arbeiten können, muss das Display bei der Initialisierung aus dem 8-Bit-Modus in den 4-Bit-Modus umgestellt werden. Dies erfolgt gemäß den Vorgaben aus dem Datenblatt durch eine spezielle Sequenz von Befehlen.

Ablauf der Initialisierung:

  1. Dreimaliges Senden des 8-Bit-Initialisierungsbefehls (0x30) im 8-Bit-Modus.

  2. Wechsel in den 4-Bit-Modus durch Senden von 0x20.

  3. Danach wird die vollständige Konfiguration im 4-Bit-Modus fortgesetzt.

Code Kopieren

void Init()
{
    Delay(40);
    SendNibble(0x4E, 0x30); 
    Delay(4.1);

    SendNibble(0x4E, 0x30);
    Delay(0.1);

    SendNibble(0x4E, 0x30);
    SendNibble(0x4E, 0x28);
    SendOrder(0x4E, 0x01);
}
    
✅ Copied!

Nach der Initialisierung können wir beliebige Befehle an das Display senden, um es nach unseren Wünschen zu konfigurieren. Diese Befehle werden im 4-Bit-Modus übertragen und ermöglichen verschiedene Einstellungen, wie:

  • Clear Display (0x01) → Löscht den Bildschirm und setzt den Cursor auf die Startposition.

  • Cursor Home (0x02) → Setzt den Cursor auf die erste Position zurück.

  • Display ON/OFF (0x0C, 0x08) → Schaltet das Display ein oder aus.

  • Cursor Steuerung (0x0E, 0x0F, 0x0C) → Aktiviert oder deaktiviert den Cursor sowie das Blinken.

  • Zeilen- und Schriftartenmodus (0x28) → Stellt das Display auf 2 Zeilen und 5×8-Zeichen ein.

Hier ist ein Beispiel, wie man die Funktion des Displays testen könnte:

Code Kopieren

    	Init();
        unsigned char string1[] = "Hello, World!"; 
        unsigned char string2[] = "LCD Display";    
        Write(string1, string2);
        
        Delay(1000); 
        SendOrder(0x4E, 0x01); 
        Delay(50);
        SendData(0x4E, 0x47);
        Delay(50);
        SendData(0x4E, 0x48);
        Delay(50);
    
✅ Copied!

BME280 – Umweltsensor

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.