/** \file I2Csensor.c \brief Treiberschicht für das kDevice812: I²C-Anbindung und LowLevel für MS5611. \author Helmut Stettmaier (stm), helmut@stettmaier.de \version 1.0 \date 15. Februar 2014 \copyright Es wurde Texte und Code-Muster aus dem LPC812-Manual übernommen. */ #include "LPC8xx.h"// Registernamen #include "LPC8xxB.h"// weitere Definitionen (nicht CMSIS) für Bit-Namen #include "hal.h" #include "I2Csensor.h" #include "main.h" void I2CCtrlResetEngine(); void I2CCtrlSendAddressWrite(); void I2CCtrlSendAddressRead(); void I2CCtrlSendResetCmd(); void I2CCtrlStartTemp(); void I2CCtrlStartPressure(); void I2CCtrlSendCalReadCmd(); void I2CCtrlReadADCCommand(); void I2CCtrlStop(); void I2CCtrlSequStop(); void I2CCtrlResetHardware(void); void I2CCtrlReadByte1(); void I2CCtrlReadByte2(); void I2CCtrlCalReadByte2(); void I2CCtrlTempReadByte3(); void I2CCtrlPressureReadByte3(); /* Note for LPC Forum readers: I²C is set up in the HAL as follows: LPC_SYSCON->SYSAHBCLKCTRL |= ( SYSCON_SYSAHBCLKCTRL_Bits | UART_SYSAHBCLKCTRL_Bits | GPIO_SYSAHBCLKCTRL_Bits | I2C_SYSAHBCLKCTRL_Bits | SCT_SYSAHBCLKCTRL_Bits); // SCT temporär für den Test-Ohrhöhrer LPC_SYSCON->PRESETCTRL= ( SYSCON_PRESETCTRL_Bits | UART_PRESETCTRL_Bits | GPIO_PRESETCTRL_Bits | I2C_PRESETCTRL_Bits | SCT_PRESETCTRL_Bits); // SCT temporär für den Test-Ohrhöhrer ... LPC_I2C->DIV= 3; // 14; LPC_I2C->CFG= 1; */ /** Die I²C-Adresse des Sensors (CS=low) */ #define MS5611_I2C_ADR 0xee /** Die 6 Kalibrierungswerte des MS5611 ohne CRC. */ uint16_t C[7]; /** Namen: C[0] ist C1 u.s.w. */ #define C1 C[1] #define C2 C[2] #define C3 C[3] #define C4 C[4] #define C5 C[5] #define C6 C[6] /** Zähler für die Kalibrierwerte-Schleife im I²C-Automaten. */ #define cnt C[0] /** Zwischengröße: Differenz zur "Referenztemperatur" in D[2]. Wird zur Kompensation des Temperatur-Fehlers im Druckwert benötigt. */ uint32_t dT; /** Export: Temperatur-kompensierter Druckwert in Pa. */ uint32_t rawPressure; /** . */ uint32_t input; /** Status des I²C-Automaten. */ uint8_t MS5611state; /** . */ #define MS5611statePanicFlag 0x80 /** Kopie von LPC_I2C->STAT. */ uint8_t cpyI2CSTAT; /** Steuer-Bit für I²C: Master - Starte Senden. */ #define MSTSTART 0x02 /** Steuer-Bit für I²C: Master - Setze Kommunikation fort. */ #define MSTCONTINUE 0x01 /** Steuer-Bit für I²C: Master - Beende Kommunikation. */ #define MSTSTOP 0x04 /** Besonderer Zustand der I2C-Engine: Setzt die Maschinerie zurück. */ #define I2CCtrlReset0 /** Besonderer Zustand der I2C-Engine: Schleifen-Beginn für die Kal.-Konstanten. */ #define I2CCtrlCalLoop4 /** Besonderer Zustand der I2C-Engine: Startet neu (ohne Rücksetzen). */ #define I2CCtrlRestart10 /** Besonderer Zustand der I2C-Engine: Endlos-Schleife für Temperatur und Druck. */ #define I2CCtrlLoop10 /** Größte erlaubte Zustands-Zahl für Bereichsmessung. */ #define I2CCtrlUppLimit29 void (*I2CCtrlTable[])() = { I2CCtrlResetEngine,// 0 /* MS5611-Reset-Kommando */ I2CCtrlSendAddressWrite,// 1 Adresse (Write)MSTSTART I2CCtrlSendResetCmd,// 2 Kommando-ByteMSTCONTINUE I2CCtrlSequStop,// 3 MSTSTOP, INTENCLR /* 6mal Kalibrier-Konstante einlesen (C[0]..C[5]) */ I2CCtrlSendAddressWrite,// 4 Adresse (Write)MSTSTART I2CCtrlSendCalReadCmd,// 5 Kommando-ByteMSTCONTINUE I2CCtrlStop,// 6 MSTSTOP I2CCtrlSendAddressRead,// 7 Adresse (Read)MSTSTART I2CCtrlReadByte1,// 8 lies 1. ByteMSTCONTINUE I2CCtrlCalReadByte2,// 9 lies 2. ByteMSTSTOP, INTENCLR /* zurück zu 4 (I2CCtrlCalLoop) falls noch Kalibrierwerte zu lesen sind */ /* Temperatur-Messung einleiten */ I2CCtrlSendAddressWrite,// 10 Adresse (Write)MSTSTART I2CCtrlStartTemp,// 11 Kommando-ByteMSTCONTINUE I2CCtrlSequStop,// 12 MSTSTOP, INTENCLR /* Temperatur-Wert einlesen und kalibrieren */ I2CCtrlSendAddressWrite,// 13 Adresse (Write)MSTSTART I2CCtrlReadADCCommand,// 14 Kommando-ByteMSTCONTINUE I2CCtrlStop,// 15 MSTSTOP I2CCtrlSendAddressRead,// 16 Adresse (Read)MSTSTART I2CCtrlReadByte1,// 17 lies 1. ByteMSTCONTINUE I2CCtrlReadByte2,// 18 lies 2. ByteMSTCONTINUE I2CCtrlTempReadByte3,// 19 lies 3. ByteMSTSTOP, INTENCLR /* Druck-Messung einleiten */ I2CCtrlSendAddressWrite,// 20 Adresse (Write)MSTSTART I2CCtrlStartPressure,// 21 Kommando-ByteMSTCONTINUE I2CCtrlSequStop,// 22 MSTSTOP, INTENCLR /* Druck-Wert einlesen und kalibrieren */ I2CCtrlSendAddressWrite,// 23 Adresse (Write)MSTSTART I2CCtrlReadADCCommand,// 24 Kommando-ByteMSTCONTINUE I2CCtrlStop,// 25 MSTSTOP I2CCtrlSendAddressRead,// 26 Adresse (Read)MSTSTART I2CCtrlReadByte1,// 27 lies 1. ByteMSTCONTINUE I2CCtrlReadByte2,// 28 lies 2. ByteMSTCONTINUE I2CCtrlPressureReadByte3// 29 lies 3. ByteMSTSTOP, INTENCLR /* zurück zu 10 (I2CCtrlLoop) */ }; /** Fehlerroutine: Mitten in der Sequenz (bei unbekanntem Zustand des I²C-Gerätes) abbrechen und die I²C-Engine auf "Neustart" setzen, Eintrag in Fehlerspeicher machen. */ void I2CCtrlAbortSequence(void) { debugRedLow;//<<<<<<<<<<<<<<<<< int i= (xErrRecord++) & 0x03; ErrRecord.tag= ErrRecordI2C; ErrRecord.subtag= MS5611state; ErrRecord.SysTickStamp= (uint16_t)(SysTickCounter) & 0xffff; ErrRecord.v.I2C.cpyI2CSTAT= cpyI2CSTAT; ErrRecord.v.I2C.currI2Cdata= input; setLED_BlinkPattern(LED_Blink_2Blinks); LPC_I2C->INTENCLR= 1; LPC_I2C->MSTCTL= MSTSTOP; debugOrangeLow;//<<<<<<<<<<<<<<<< cnt= 6; MS5611state= (I2CCtrlRestart-1) | MS5611statePanicFlag; debugRedHigh;//<<<<<<<<<<<<<<< } /** Sende die MS5611-Adresse (als Beginn einer I²C-Kommandosequenz). */ void I2CCtrlSendAddressWrite(void) { LPC_SYSCON->SYSAHBCLKCTRL|= (I2C_SYSAHBCLKCTRL_Bits); LPC_SYSCON->PRESETCTRL|= (I2C_PRESETCTRL_Bits); debugOrangeHigh;//<<<<<<<<<< LPC_I2C->MSTDAT= MS5611_I2C_ADR; LPC_I2C->MSTCTL= MSTSTART; LPC_I2C->INTENSET= 1; input= 0; }; /** Beende eine I²C-Kommandosequenz. */ void I2CCtrlSequStop(void) { LPC_I2C->MSTCTL= MSTSTOP; LPC_I2C->INTENCLR= 1; // löst nicht mehr aus. } /** Reset I²C Hardware. Panik! */ void I2CCtrlResetHardware(void) { debugOrangeHigh;//<<<<<<<<<<< LPC_SYSCON->PRESETCTRL&= ~(I2C_PRESETCTRL_Bits); LPC_SYSCON->SYSAHBCLKCTRL&= ~ (I2C_SYSAHBCLKCTRL_Bits); MS5611state&= ~MS5611statePanicFlag; debugOrangeLow;//<<<<<<<<<< } /** Setze den I²C-Automaten zurück. */ void I2CCtrlResetEngine(void) { cnt= 6; MS5611state= 0; } /** Sende die MS5611-Adresse zum Lesen. */ void I2CCtrlSendAddressRead(void) { if (cpyI2CSTAT==1 /* ist I²C idle? */) { LPC_I2C->MSTDAT= MS5611_I2C_ADR | 1; LPC_I2C->MSTCTL= MSTSTART; } else I2CCtrlAbortSequence(); }; /** Sende den Reset-Befehl als Datenbyte. */ void I2CCtrlSendResetCmd(void) { //if (cpyI2CSTAT==5 /* Transmit_ready? */) { LPC_I2C->MSTDAT= 0x1e; LPC_I2C->MSTCTL= MSTCONTINUE; //} else I2CCtrlAbortSequence(); } /** Sende das Initialize-Temperature-Measurement-Kommando als Datenbyte. */ void I2CCtrlStartTemp(void) { LPC_I2C->MSTDAT= 0x58; LPC_I2C->MSTCTL= MSTCONTINUE; } /** Sende das Initialize-Pressure-Measurement-Kommando als Datenbyte. */ void I2CCtrlStartPressure(void) { LPC_I2C->MSTDAT= 0x48; LPC_I2C->MSTCTL= MSTCONTINUE; } /** Sende das CalConst-Lese-Kommando als Datenbyte. cnt ist # der CalConst. */ void I2CCtrlSendCalReadCmd(void) { LPC_I2C->MSTDAT= 0xa0 | (cnt<<1); LPC_I2C->MSTCTL= MSTCONTINUE; } /** . */ void I2CCtrlReadADCCommand(void) { //if (cpyI2CSTAT==5 /* Transmit_ready? */) { LPC_I2C->MSTDAT= 0x00; LPC_I2C->MSTCTL= MSTCONTINUE; //} else I2CCtrlAbortSequence(); } /** Sende Stop-Condition, lasse den Interrupt aber eingeschaltet. */ void I2CCtrlStop(void) { LPC_I2C->MSTCTL= MSTSTOP; // sendet STOP und löst sofort mit IDLE wieder aus } /** Lesen: 1. Byte. */ void I2CCtrlReadByte1(void) { if (cpyI2CSTAT==3 /* Read_ready? */) { input= LPC_I2C->MSTDAT; LPC_I2C->MSTCTL= MSTCONTINUE; } else I2CCtrlAbortSequence(); } /** Lesen: 2. Byte (neutral). */ void I2CCtrlReadByte2(void) { if (cpyI2CSTAT==3 /* Read_ready? */) { input= input<<8 | LPC_I2C->MSTDAT; LPC_I2C->MSTCTL= MSTCONTINUE; } else I2CCtrlAbortSequence(); } /** Kalibrier-Konstante lesen: 2. Byte, zusammensetzen & abspeichern. cnt ist # der CalConst. */ void I2CCtrlCalReadByte2(void) { if (cpyI2CSTAT==3 /* Read_ready? */) { C[cnt]= input<<8 | LPC_I2C->MSTDAT; /* Es müssen 6 Konstanten eingelesen werden: C[6]..C[1]. Dies wird mit cnt (von 0 bis 5) gezählt. Wenn cnt also noch <6 ist muss dieser Lesevorgang wiederholt werden; dazu wird (ugly) einfach MS5611state zurück gestellt. */ if (--cnt) MS5611state= I2CCtrlCalLoop-1; /* Sende Stop-Condition und beende die Sequenz. */ LPC_I2C->MSTCTL= MSTSTOP; LPC_I2C->INTENCLR= 1; } else I2CCtrlAbortSequence(); } /** Lies das 3. Byte des Temperatur-Wertes ein, Berechne dT. */ void I2CCtrlTempReadByte3(void) { uint32_t D2= input<<8 | LPC_I2C->MSTDAT; dT = D2 - (((int32_t)(C5)) << 8); LPC_I2C->MSTCTL= MSTSTOP; } /** Lies das 3. Byte des Druck-Wertes ein, Berechne dT. */ void I2CCtrlPressureReadByte3(void) { int64_t s, o; uint32_t D1= input<<8 | LPC_I2C->MSTDAT; o =(((int64_t)(C2))<<16)+ (((C4)* (int64_t)dT)>>7); s =(((int64_t)(C1))<<15)+ (((C3)* (int64_t)dT)>>8); rawPressure =((((int64_t)D1 *s)>>21) -o)>>15; LPC_I2C->MSTCTL= MSTSTOP; mainStatus|= mstatMS5611PrValread; MS5611state= I2CCtrlLoop-1; } /** Start des MS5611-Abfrage-Automaten. */ void resetMS5611(void) { set_mrt_repeatedmode (2, (110*__SYSCLOCK_100us)); // 11ms MS5611state= 0; } /* Note for readers from LPC-Forum: I2C_MRTaction is part of the MRT-Interrupt handler which is copied here: void MRT_IRQHandler(void) { if (LPC_MRT->Channel[2].STAT & MRT_STAT_IRQ_FLAG) { LPC_MRT->Channel[2].STAT = MRT_STAT_IRQ_FLAG; I2C_MRTaction(); } if (LPC_MRT->Channel[3].STAT & MRT_STAT_IRQ_FLAG) { LPC_MRT->Channel[3].STAT = MRT_STAT_IRQ_FLAG; MSBRxTiming(); } NVIC->ICPR[0] |= MRT_INTERRUPT_BIT; return; } */ /** Bearbeitet den für den I²C-Verkehr ausgelösten MRT-Interrupt: Startet die nächste anstehende I²C-Kommandosequenz. */ inline void I2C_MRTaction(void) { cpyI2CSTAT= LPC_I2C->STAT; if (MS5611state>I2CCtrlUppLimit) MS5611state= 0; // panic (*I2CCtrlTable[MS5611state])(); MS5611state++; return; } /** I²C-Interrupt: Setzt die laufende I²C-Kommandosequenz fort. */ void I2C_IRQHandler(void) { cpyI2CSTAT= LPC_I2C->STAT; if (MS5611state>I2CCtrlUppLimit) MS5611state= 0; // panic if (MS5611state & MS5611statePanicFlag) I2CCtrlResetHardware(); else { (*I2CCtrlTable[MS5611state])(); MS5611state++; } return; } /* Note for readers from LPC-Forum: This is a data record for logging faults; it is used in the error repai function: typedef struct sErrRecord { uint8_t tag; uint8_t subtag; uint16_t SysTickStamp; union uErrRecord { uint32_t unspecified; struct sI2C { uint32_t currI2Cdata; uint8_t cpyI2CSTAT; } I2C; } v; } tErrRecord; */ /** Tag für Fehleraufzeichnung, identifiziert I²C-Fehler. */ #define ErrRecordI2C 1 /** Schreibt eine I²C-Fehlermeldung in das Fehler-Log. \param stwird als SubTag eingetragen. */ void wErrRecordI2C(void) { disableInterrupts; int i= (xErrRecord++) & 0x03; ErrRecord.tag= ErrRecordI2C; ErrRecord.subtag= MS5611state; ErrRecord.SysTickStamp= (uint16_t)(SysTickCounter) & 0xffff; ErrRecord.v.I2C.cpyI2CSTAT= cpyI2CSTAT; ErrRecord.v.I2C.currI2Cdata= input; enableInterrupts; setLED_BlinkPattern(LED_Blink_2Blinks); } |
void MRT_IRQHandler(void) { NVIC->ICPR[0] = MRT_INTERRUPT_BIT; checkallMRTints: if (LPC_MRT->Channel[3].STAT & MRT_STAT_IRQ_FLAG) { LPC_MRT->Channel[3].STAT = MRT_STAT_IRQ_FLAG; MSBRxTiming(); } if (LPC_MRT->Channel[2].STAT & MRT_STAT_IRQ_FLAG) { LPC_MRT->Channel[2].STAT = MRT_STAT_IRQ_FLAG; I2C_MRT_Action(); goto checkallMRTints; } return; } |
LPC_SYSCON->PRESETCTRL &= ~I2C_PRESETCTRL_Bits; LPC_SYSCON->PRESETCTRL |= I2C_PRESETCTRL_Bits; LPC_I2C->DIV= 3; // don't forget to define the clock divider again LPC_I2C->CFG= 1; // don't forget to set Master function again LPC_I2C->TIMEOUT= 0x002f; // and don't forget to set timeout again when you use it. // LPC_I2C->INTENSET= (MSTPENDINGEN | EVENTTIMEOUTEN); // and don't forget this... |
/** \file I2Csensor.c \brief Treiberschicht für das kDevice812: I²C-Anbindung und LowLevel für MS5611. \author Helmut Stettmaier (stm) \version 1.0 \date ... 2014 */ #include "LPC8xx.h"// Registernamen #include "LPC8xxB.h"// weitere Definitionen (nicht CMSIS) für Bit-Namen #include "hal.h" #include "I2Csensor.h" #include "main.h" void I2CCtrlStartSequence(); void I2CCtrlSendAddressRead(); void I2CCtrlSendResetCmd(); void I2CCtrlStartTemp(); void I2CCtrlStartPressure(); void I2CCtrlSendCalReadCmd(); void I2CCtrlReadADCCommand(); void I2CCtrlStop(); void I2CCtrlSequStop(); void I2CCtrlResetHardware(void); void I2CCtrlReadByte1(); void I2CCtrlReadByte2(); void I2CCtrlCalReadByte2(); void I2CCtrlTempReadByte3(); void I2CCtrlPressureReadByte3(); void writeI2CErrRecord(unsigned int v); /* Note for LPC Forum readers: I²C is set up in the HAL as follows: LPC_SYSCON->SYSAHBCLKCTRL |= ( SYSCON_SYSAHBCLKCTRL_Bits | UART_SYSAHBCLKCTRL_Bits | GPIO_SYSAHBCLKCTRL_Bits | I2C_SYSAHBCLKCTRL_Bits | SCT_SYSAHBCLKCTRL_Bits); // SCT temporär für den Test-Ohrhöhrer LPC_SYSCON->PRESETCTRL= ( SYSCON_PRESETCTRL_Bits | UART_PRESETCTRL_Bits | GPIO_PRESETCTRL_Bits | I2C_PRESETCTRL_Bits | SCT_PRESETCTRL_Bits); // SCT temporär für den Test-Ohrhöhrer ... LPC_I2C->DIV= 3; // 14; LPC_I2C->CFG= 1; LPC_I2C->TIMEOUT= 0x002f; // -->48 */ /** Die I²C-Adresse des Sensors (CS=low) */ #define MS5611_I2C_ADR 0xee /** Die 6 Kalibrierungswerte des MS5611 ohne CRC. */ static uint16_t C[7]; /** Namen: C[1] ist C1 u.s.w. */ #define C1 C[1] #define C2 C[2] #define C3 C[3] #define C4 C[4] #define C5 C[5] #define C6 C[6] /** Zähler für die Kalibrierwerte-Schleife im I²C-Automaten. */ static uint8_t cnt; /** Status des I²C-Automaten. */ uint8_t MS5611state; /** Zwischengröße: Differenz zur "Referenztemperatur" in D[2]. Wird zur Kompensation des Temperatur-Fehlers im Druckwert benötigt. */ uint32_t dT; /** Export: Temperatur-kompensierter Druckwert in Pa. */ uint32_t rawPressure; /** . */ static uint32_t input; /** Start des MS5611-Abfrage-Automaten. */ void resetMS5611(void) { set_mrt_repeatedmode (2, (110*__SYSCLOCK_100us)); // 11ms MS5611state= 0; cnt= 6; input= 0; } /** Wert von LPC_I2C->STAT. */ static uint32_t cpyI2CSTAT; /** Steuer-Bit für I²C: Master - Starte Senden. */ #define MSTSTART 0x02 /** Steuer-Bit für I²C: Master - Setze Kommunikation fort. */ #define MSTCONTINUE 0x01 /** Steuer-Bit für I²C: Master - Beende Kommunikation. */ #define MSTSTOP 0x04 /** Besonderer Zustand der I2C-Engine: Setzt die Maschinerie zurück. */ #define I2CCtrlReset0 /** Besonderer Zustand der I2C-Engine: Schleifen-Beginn für die Kal.-Konstanten. */ #define I2CCtrlCalLoop3 /** Besonderer Zustand der I2C-Engine: Startet neu (ohne Rücksetzen). */ #define I2CCtrlRestart9 /** Besonderer Zustand der I2C-Engine: Endlos-Schleife für Temperatur und Druck. */ #define I2CCtrlLoop12 /** Größte erlaubte Zustands-Zahl für Bereichsprüfung. */ #define I2CCtrlUppLimit31 //void (*I2CCtrlTable[])() = { /** . */ typedef void (* I2Cstep)(void); /** . */ const I2Cstep I2CCtrlTable[]= { /* MS5611-Reset-Kommando */ I2CCtrlStartSequence,// 0 Adresse (Write)MSTSTART I2CCtrlSendResetCmd,// 1 Kommando-ByteMSTCONTINUE I2CCtrlSequStop,// 2 MSTSTOP, INTENCLR /* 6mal Kalibrier-Konstante einlesen (C[1]..C[6]) */ I2CCtrlStartSequence,// 3 Adresse (Write)MSTSTART I2CCtrlSendCalReadCmd,// 4 Kommando-ByteMSTCONTINUE I2CCtrlStop,// 5 MSTSTOP I2CCtrlSendAddressRead,// 6 Adresse (Read)MSTSTART I2CCtrlReadByte1,// 7 lies 1. ByteMSTCONTINUE I2CCtrlCalReadByte2,// 8 lies 2. ByteMSTSTOP, INTENCLR /* zurück zu 4 (I2CCtrlCalLoop) falls noch Kalibrierwerte zu lesen sind */ /* MS5611-Reset-Kommando */ I2CCtrlStartSequence,// 9 Adresse (Write)MSTSTART I2CCtrlSendResetCmd,// 10 Kommando-ByteMSTCONTINUE I2CCtrlSequStop,// 11 MSTSTOP, INTENCLR /* Temperatur-Messung einleiten */ I2CCtrlStartSequence,// 12 Adresse (Write)MSTSTART I2CCtrlStartTemp,// 13 Kommando-ByteMSTCONTINUE I2CCtrlSequStop,// 14 MSTSTOP, INTENCLR /* Temperatur-Wert einlesen und kalibrieren */ I2CCtrlStartSequence,// 15 Adresse (Write)MSTSTART I2CCtrlReadADCCommand,// 16 Kommando-ByteMSTCONTINUE I2CCtrlStop,// 17 MSTSTOP I2CCtrlSendAddressRead,// 18 Adresse (Read)MSTSTART I2CCtrlReadByte1,// 19 lies 1. ByteMSTCONTINUE I2CCtrlReadByte2,// 20 lies 2. ByteMSTCONTINUE I2CCtrlTempReadByte3,// 21 lies 3. ByteMSTSTOP, INTENCLR /* Druck-Messung einleiten */ I2CCtrlStartSequence,// 22 Adresse (Write)MSTSTART I2CCtrlStartPressure,// 23 Kommando-ByteMSTCONTINUE I2CCtrlSequStop,// 24 MSTSTOP, INTENCLR /* Druck-Wert einlesen und kalibrieren */ I2CCtrlStartSequence,// 25 Adresse (Write)MSTSTART I2CCtrlReadADCCommand,// 26 Kommando-ByteMSTCONTINUE I2CCtrlStop,// 27 MSTSTOP I2CCtrlSendAddressRead,// 28 Adresse (Read)MSTSTART I2CCtrlReadByte1,// 29 lies 1. ByteMSTCONTINUE I2CCtrlReadByte2,// 30 lies 2. ByteMSTCONTINUE I2CCtrlPressureReadByte3// 31 lies 3. ByteMSTSTOP, INTENCLR /* zurück zu 10 (I2CCtrlLoop) */ }; /** Sende die MS5611-Adresse (als Beginn einer I²C-Kommandosequenz). */ void I2CCtrlStartSequence(void) { LPC_I2C->MSTDAT= MS5611_I2C_ADR; LPC_I2C->MSTCTL= MSTSTART; debugRedHigh;//<<<<<<<<<<<<<<<<< LPC_I2C->INTENSET= (MSTPENDINGEN | EVENTTIMEOUTEN); input= 0; }; /** Beende eine I²C-Kommandosequenz. */ void I2CCtrlSequStop(void) { LPC_I2C->INTENCLR= 1; LPC_I2C->MSTCTL= MSTSTOP; } /** Sende die MS5611-Adresse zum Lesen. */ void I2CCtrlSendAddressRead(void) { LPC_I2C->MSTDAT= MS5611_I2C_ADR | 1; LPC_I2C->MSTCTL= MSTSTART; }; /** Sende den Reset-Befehl als Datenbyte. */ void I2CCtrlSendResetCmd(void) { LPC_I2C->MSTDAT= 0x1e; LPC_I2C->MSTCTL= MSTCONTINUE; } /** Sende das Initialize-Temperature-Measurement-Kommando als Datenbyte. */ void I2CCtrlStartTemp(void) { LPC_I2C->MSTDAT= 0x58; LPC_I2C->MSTCTL= MSTCONTINUE; } /** Sende das Initialize-Pressure-Measurement-Kommando als Datenbyte. */ void I2CCtrlStartPressure(void) { LPC_I2C->MSTDAT= 0x48; LPC_I2C->MSTCTL= MSTCONTINUE; } /** Sende das CalConst-Lese-Kommando als Datenbyte. cnt ist # der CalConst. */ void I2CCtrlSendCalReadCmd(void) { LPC_I2C->MSTDAT= 0xa0 | (cnt<<1); LPC_I2C->MSTCTL= MSTCONTINUE; } /** . */ void I2CCtrlReadADCCommand(void) { LPC_I2C->MSTDAT= 0x00; LPC_I2C->MSTCTL= MSTCONTINUE; } /** Sende Stop-Condition, lasse den Interrupt aber eingeschaltet. */ void I2CCtrlStop(void) { LPC_I2C->MSTCTL= MSTSTOP; } /** Lesen: 1. Byte. */ void I2CCtrlReadByte1(void) { input= LPC_I2C->MSTDAT; LPC_I2C->MSTCTL= MSTCONTINUE; } /** Lesen: 2. Byte (neutral). */ void I2CCtrlReadByte2(void) { input= input<<8 | LPC_I2C->MSTDAT; LPC_I2C->MSTCTL= MSTCONTINUE; } /** Kalibrier-Konstante lesen: 2. Byte, zusammensetzen & abspeichern. cnt ist # der CalConst. */ void I2CCtrlCalReadByte2(void) { C[cnt]= input<<8 | LPC_I2C->MSTDAT; if (--cnt) MS5611state= I2CCtrlCalLoop-1; LPC_I2C->MSTCTL= MSTSTOP; LPC_I2C->INTENCLR= 1; } /** Lies das 3. Byte des Temperatur-Wertes ein, Berechne dT. */ void I2CCtrlTempReadByte3(void) { uint32_t D2= input<<8 | LPC_I2C->MSTDAT; dT = D2 - (((int32_t)(C5)) << 8); LPC_I2C->MSTCTL= MSTSTOP; } /** Lies das 3. Byte des Druck-Wertes ein, Berechne den Roh-Druckwert. */ void I2CCtrlPressureReadByte3(void) { int64_t s, o; uint32_t D1= input<<8 | LPC_I2C->MSTDAT; o =(((int64_t)(C2))<<16)+ (((C4)* (int64_t)dT)>>7); s =(((int64_t)(C1))<<15)+ (((C3)* (int64_t)dT)>>8); rawPressure =((((int64_t)D1 *s)>>21) -o)>>15; LPC_I2C->MSTCTL= MSTSTOP; mainStatus|= mstatMS5611PrValread; MS5611state= I2CCtrlLoop-1; } /* Note for readers from LPC-Forum: I2C_MRTaction is part of the MRT-Interrupt handler which is copied here: void MRT_IRQHandler(void) { if (LPC_MRT->Channel[2].STAT & MRT_STAT_IRQ_FLAG) { LPC_MRT->Channel[2].STAT = MRT_STAT_IRQ_FLAG; debugYellowLow; //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< I2C_MRTaction(); debugYellowHigh; //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } if (LPC_MRT->Channel[3].STAT & MRT_STAT_IRQ_FLAG) { LPC_MRT->Channel[3].STAT = MRT_STAT_IRQ_FLAG; debugBlueLEDon; //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< MSBRxTiming(); debugBlueLEDoff; //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } NVIC->ICPR[0] = MRT_INTERRUPT_BIT; return; } */ /** Bearbeitet den für den I²C-Verkehr ausgelösten MRT-Interrupt: Startet die nächste anstehende I²C-Kommandosequenz. */ inline void I2C_MRTaction(void) { if (MS5611state>I2CCtrlUppLimit) { debugRedLow;//<<<<<<<<<<<<<<<<<< writeI2CErrRecord(3); mainStatus&= ~mstatMS5611PrValread; MS5611state= I2CCtrlRestart; } if (!(LPC_I2C->STAT & MSTPENDING)) { debugRedLow;//<<<<<<<<<<<<<<<<<< writeI2CErrRecord(1); _Panic_; // still write a panic handler <<<<<<<<< } I2CCtrlStartSequence(); // ex (*I2CCtrlTable[MS5611state])(); MS5611state++; return; } /** I²C-Interrupt: Setzt die laufende I²C-Kommandosequenz fort. */ void I2C_IRQHandler(void) { cpyI2CSTAT= LPC_I2C->STAT; debugOrangeLow; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< if (MS5611state>I2CCtrlUppLimit) { mainStatus&= ~mstatMS5611PrValread; MS5611state= I2CCtrlRestart; } if (!(cpyI2CSTAT & MSTPENDING)) { writeI2CErrRecord(2); _Panic_; // still write a panic handler <<<<<<<<< } if (cpyI2CSTAT & EVENTTIMEOUT || ((cpyI2CSTAT & MSTSTATEMASK)==MSTADDRNAK) || ((cpyI2CSTAT & MSTSTATEMASK)==MSTDATANAK)) { // ugly //debugRedLow;//<<<<<<<<<<<<<<<<<< writeI2CErrRecord(0); setLED_BlinkPattern(LED_Blink_2Blinks); LPC_I2C->STAT |= EVENTTIMEOUT; LPC_I2C->INTENCLR= (MSTPENDINGEN | EVENTTIMEOUTEN); LPC_I2C->MSTCTL= MSTSTOP; mainStatus&= ~mstatMS5611PrValread; cnt= 6; MS5611state= I2CCtrlRestart; } else { (*I2CCtrlTable[MS5611state])(); MS5611state++; } debugOrangeHigh; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< return; } void writeI2CErrRecord(unsigned int v) { int i= (xErrRecord++) & 0x07; ErrRecord.tag= ErrRecordI2C+v; ErrRecord.subtag= MS5611state; ErrRecord.SysTickStamp= (uint16_t)(SysTickCounter); ErrRecord.v.I2C.I2CSTAT= cpyI2CSTAT; ErrRecord.v.I2C.currI2Cdata= input; } |