/** \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;
}
|