Hi
Mein 4Kanal Logger, der über mehrere Tage 4 Spannungen überwachen soll,
hängt sich nach 30-120min auf. Das Programm bleibt stehen, die Zeit
ändert sich nicht mehr und das Display zeigt den alten Wert an. Sobald
man die Stromversorgung kappt, funktioniert alles wieder.
Das Atmega hängt an einem externem Quarz. Die Platine ist
Streifenraster, das sollte aber nicht das Problem sein.
Um zu hängen müsste das Programm doch in einer Endlosschleife hängen,
die einzigen, die es gibt, sind von den I2C Routinen (fertige Lib).
Das ist die Hautpschleife, in der er sich aufhängt: 1 | #define CLKDIV 24000
| 2 | volatile uint16_t sprescaler = 0;
| 3 | volatile uint8_t next = 0;
| 4 | volatile uint8_t sec = 0;
| 5 | volatile uint16_t count;
| 6 | uint16_t Mcount, hours;
| 7 | uint8_t secs, mins;
| 8 |
| 9 | void rec(void)
| 10 | {
| 11 | count = pgm_read_word(&(intervall_int[Vintervall]));
| 12 | StartTimer();
| 13 | lcd_clear();
| 14 | NewStream(Vchannels + 1);
| 15 | uint8_t b = 0;
| 16 | Mcount = 0;
| 17 | secs = mins = hours = 0;
| 18 | do
| 19 | {
| 20 | cli();
| 21 | if(next)
| 22 | {
| 23 | for(uint8_t i = 0; i <= Vchannels; i++)
| 24 | WriteBuffer13(ADC_Read13(i));
| 25 | Mcount++;
| 26 | b = 1 - b;
| 27 | next = 0;
| 28 | }
| 29 | if(key_update_req)
| 30 | key_update();
| 31 | if(sec)
| 32 | {
| 33 | secs += sec;
| 34 | sec = 0;
| 35 | while(secs >= 60)
| 36 | {
| 37 | secs = 0;
| 38 | if(++mins == 60)
| 39 | {
| 40 | mins = 0;
| 41 | ++hours;
| 42 | }
| 43 | }
| 44 | lcd_setcursor(0, 1);
| 45 | for(uint8_t i = 0; i <= Vchannels; i++)
| 46 | {
| 47 | print13s(ADC_Read13(i));
| 48 | if(i != Vchannels)
| 49 | lcd_putc(' ');
| 50 | }
| 51 | lcd_putc('V');
| 52 | lcd_setcursor(0, 2);
| 53 | char buff[6];
| 54 | itoa16(Mcount, buff);
| 55 | lcd_puts(buff);
| 56 | itoa16(hours, buff);
| 57 | lcd_puts(buff);
| 58 | lcd_putc(':');
| 59 | itoa8(mins, buff);
| 60 | lcd_puts(buff + 1);
| 61 | lcd_putc(':');
| 62 | itoa8(secs, buff);
| 63 | lcd_puts(buff + 1);
| 64 | }
| 65 | sei();
| 66 | }
| 67 | while(UP(BACK));
| 68 | StopTimer();
| 69 | ClearBuffer();
| 70 | }
|
Die kleinen Routinen StartTimer und StopTimer steuern den 16bit Timer,
die ISR zählt die Sekunden (sec) und steuert auch wann die nächste
Messung durchgeführt wird: 1 | void StartTimer(void)
| 2 | {
| 3 | cli();
| 4 | TCCR1B |= (1 << CS12) | (1 << WGM12); //Prescaler 256 + CTC
| 5 | OCR1A = CLKDIV - 1;
| 6 | TIMSK |= 1 << OCIE1A; //Compare Match interrupt erlauben
| 7 | sei();
| 8 | }
| 9 | void StopTimer(void)
| 10 | {
| 11 | cli();
| 12 | TIMSK &= ~(1 << OCIE1A); //Compare Match interrupt deaktivieren
| 13 | sei();
| 14 | }
| 15 | ISR (TIMER1_COMPA_vect)
| 16 | {
| 17 | sec++;
| 18 | if(sprescaler == 0)
| 19 | {
| 20 | sprescaler = count;
| 21 | next = 1;
| 22 | }
| 23 | sprescaler--;
| 24 | }
|
Hier sind noch die Routinen des "Dateisystems":
1 | //FORMAT: xxxDDDDD DDDDDDDD
| 2 | // D = Data
| 3 | // x: 111 = Ende
| 4 | // 000 = In Stream
| 5 | // xxx = Neuer Stream mit xxx Kanälen
| 6 |
| 7 | #define BUFFERLEN 64
| 8 | #define WRITE(pos,buf,count) i2cMemWrite(0xA0,pos,buf,count,0)
| 9 | #define READ(pos,buf,count) i2cMemRead(0xA0,pos,buf,count)
| 10 |
| 11 | uint16_t streampos = 0;
| 12 | uint8_t buffer[BUFFERLEN];
| 13 | uint8_t bufferpos = 0;
| 14 | uint8_t newstream = 0;
| 15 |
| 16 | uint16_t GetStreamEnd(void)
| 17 | {
| 18 | uint8_t rbuffer[BUFFERLEN];
| 19 | for(uint16_t pos = 0; pos < 16384 ; pos += BUFFERLEN)
| 20 | {
| 21 | READ(pos, rbuffer, BUFFERLEN);
| 22 | for(uint8_t i = 0; i < BUFFERLEN; i += 2)
| 23 | if(rbuffer[i] == 0xFF)
| 24 | return pos + i;
| 25 | }
| 26 | return 0;
| 27 | }
| 28 |
| 29 | void NewStream(uint8_t channels)
| 30 | {
| 31 | if(streampos == 0)
| 32 | streampos = GetStreamEnd();
| 33 | newstream = channels << 5;
| 34 | }
| 35 |
| 36 | void WriteBuffer13(uint16_t data)
| 37 | {
| 38 | WriteBuffer8((uint8_t)((data >> 8) | newstream));
| 39 | WriteBuffer8((uint8_t) data);
| 40 | newstream = 0;
| 41 | }
| 42 |
| 43 | void WriteBuffer8(uint8_t data)
| 44 | {
| 45 | buffer[bufferpos++] = data;
| 46 | streampos++;
| 47 | if((((uint8_t)streampos) & (BUFFERLEN - 1)) == 0 || bufferpos == BUFFERLEN)
| 48 | ClearBuffer();
| 49 | }
| 50 |
| 51 | void ClearBuffer(void)
| 52 | {
| 53 | WRITE(streampos - bufferpos, buffer, bufferpos);
| 54 | buffer[BUFFERLEN - 1] = 0;
| 55 | uart_puts(buffer);
| 56 | bufferpos = 0;
| 57 | }
|
das kann schon sein, das das I2C mal hängt. Eigentlich sollten sich aber
alle Fehler abfangen lassen.
Deaktiviere doch mal das Aufzeichnen und schau ob's dann läuft.
Sascha
Sascha Weber schrieb:
> Deaktiviere doch mal das Aufzeichnen und schau ob's dann läuft.
Danke für die Antwort. Ich werde das morgen mal probieren (heute wird
das nichts mehr, da ich nicht genau weiß wann der Fehler eintritt).
Watchdog wäre auch eine Möglichkeit, aber das gefällt mir nicht so, da
ich die so Sachen wie Intervall und Startzeit im internen EEprom
speichern, oder nochmal das "Dateisystem" überarbeiten müsste.
So...
Ich hab grad die if Abfrage geändert
if(next && Vsave)
{
for(uint8_t i = 0; i <= Vchannels; i++)
WriteBuffer13(ADC_Read13(i));
Mcount++;
b = 1 - b;
next = 0;
}
Vsave hab ich über das Menu auf 0 gestellt. In ein paar Stunden schau
ich nochmal ob sich was geändert hat.
PS: irgendwie muss ich gerade an www.if-schleife.de denken.
Das Programm lüuft nun fast 7 Stunden ohne Unterbrechung. Der Fehler
muss wirklich in der Speicher-Funktion liegen.
Ich glaube aber den Fehler gefunden zu haben:
Beitrag "Re: Hardware TWI,I²C, I²C EEPROM"
> Beim Versuch, im laufenden Betrieb größere Mengen Daten aus dem EEPROM
> zu lesen, schmiert alles ab. Es scheint mir, dass der INT in die
> i2c-Routinen reinfunkt.
Mir scheint der Keyboard-Interrupt funkt zufällig in die I2C
Schreibroutine rein. Mal schauen was passiert wenn ich den Interrupt
voher abschalte.
Samuel K. schrieb:
> Ich glaube aber den Fehler gefunden zu haben:
Nein, doch nicht. Ich hatte die Interrupts schon vorher ausgeschaltet.
Diesmal ist es nach genau 31 Messungen abgestürzt.
Ich werde mal soft i2c verwenden.
Hat noch jemand eine Idee was da nicht funktionieren könnte?
Hmm, langsam dreh ich durch. Jetzt bekomm ich es nicht mal mehr hin ein
EEPROM zu beschreiben.
Ich habe diese lib genommen
(Beitrag "I2C-Master [ohne TWI (Softwarelösung) für die ATMEGAs"). 1 | void i2cWrite(uint8_t adress, uint16_t pos, uint8_t *buf, uint8_t count)
| 2 | {
| 3 | i2c_master_start();
| 4 | i2c_master_write(adress);
| 5 | i2c_master_write(pos >> 8);
| 6 | i2c_master_write(pos & 0xFF);
| 7 | while(count--)
| 8 | i2c_master_write(*buf++);
| 9 | i2c_master_stop();
| 10 | }
| 11 | void i2cRead(uint8_t adress, uint16_t pos, uint8_t *buf, uint8_t count)
| 12 | {
| 13 | i2c_master_start();
| 14 | i2c_master_write(adress + 1);
| 15 | while(count--)
| 16 | *buf++ = i2c_master_read(0);
| 17 | i2c_master_stop();
| 18 | }
|
Read funktioniert ganz gut, aber bei Write bleibt er hängen.
Im Datenblatt
(http://www.atmel.com/dyn/resources/prod_documents/doc0670.pdf) steht:
start,adresse, high-adresse (0xA0), low-adr, n*data, stop.
Das hab ich doch gemacht. Trotzdem will das nicht.
die Lib oben ist aber Soft-I2C, welche Lib hast du zuerst verwendet?
Was für einen EEProm hast du dran?
in deiner READ Funktion 1 | void i2cRead(uint8_t adress, uint16_t pos, uint8_t *buf, uint8_t count)
| 2 | {
| 3 | i2c_master_start();
| 4 | i2c_master_write(adress + 1);
| 5 | while(count--)
| 6 | *buf++ = i2c_master_read(0);
| 7 | i2c_master_stop();
| 8 | }
|
sehe ich nix wie du die Readadresse einstellst! Und du beendest das
lesen eigentlich nicht ordungsgemäß, denn das letzte Byte sollte mit
NACK bestätigt werden.
Sascha
Sascha Weber schrieb:
> sehe ich nix wie du die Readadresse einstellst! Und du beendest das
> lesen eigentlich nicht ordungsgemäß, denn das letzte Byte sollte mit
> NACK bestätigt werden.
Danke, das wusste ich nicht. Leseadresse habe ich vergessen, aber da ich
immer von anfang gelesen habe, war es auch nicht weiter schlimm.
1 | void i2cRead(uint8_t adress, uint16_t pos, uint8_t *buf, uint8_t count)
| 2 | {
| 3 | if(count == 0)
| 4 | return;
| 5 | i2c_master_start();
| 6 | i2c_master_write(adress + 1);
| 7 | i2c_master_write(pos >> 8);
| 8 | i2c_master_write(pos & 0xFF);
| 9 | while(--count)
| 10 | *buf++ = i2c_master_read(0);
| 11 | *buf = i2c_master_read(1);
| 12 | i2c_master_stop();
| 13 | }
|
Sascha Weber schrieb:
> die Lib oben ist aber Soft-I2C, welche Lib hast du zuerst verwendet?
> Was für einen EEProm hast du dran?
Ich verwende diese Lib
Beitrag "Hardware TWI,I²C, I²C EEPROM"
mit dem Update
Beitrag "Re: Hardware TWI,I²C, I²C EEPROM"
EEPROM ist das Datenblatt das ich verlinkt habe: 24C128 von Atmel
Trotzdem gleiches Problem. Das schreiben funktioniert nicht. Nach 7
Messungen hängt der µC (8 * 4 Kanäle * 2 Byte = 64 Byte = 1Page, da 64B
Buffer)
wenn der µC hängt, dann prüfe doch mal den Pegel der I2C-Leitungen und
ob sich dort noch was tut.
Mach dir zwischen den einzelnen I2C Funktionen noch ein paar
Debugausgaben auf den UART damit du siehst wo es hängt.
Sascha
Sascha Weber schrieb:
> wenn der µC hängt, dann prüfe doch mal den Pegel der I2C-Leitungen und
> ob sich dort noch was tut.
Für mich schwer zu realisieren. Ich könnte nächste Woche evtl. ein Oszi
dranhängen. Einen Logikanalyser besitze ich nicht.
> Mach dir zwischen den einzelnen I2C Funktionen noch ein paar
> Debugausgaben auf den UART damit du siehst wo es hängt.
OK. 14 Bytes schreibt er, beim 15 hängt er.
Aber entweder die Lesefunktion funktioniert nicht, oder die Bytes werden
nicht richtig geschrieben, denn ich kann sie nicht empfangen.
Danke für deine Bemühungen Sascha. Nach längerem Probieren und
Vergleichen mit dem älteren Backup hab ich glaubich den Fehler gefunden:
Samuel K. schrieb:
> void ClearBuffer(void)
> {
> WRITE(streampos - bufferpos, buffer, bufferpos);
> buffer[BUFFERLEN - 1] = 0;
> uart_puts(buffer);
> bufferpos = 0;
> }
Hier sind die Interrupts deaktiviert. Der Uart-Buffer hab aber nur 64
Zeichen. Also wird gewartet bis dieser frei ist, was aber so nie sein
wird.
Mit der (hardware) i2c lib funktioniert es jetzt (hoffentlich).
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|