Forum: Mikrocontroller und Digitale Elektronik xmega eeprom Probleme


von Philip P. (nerb)


Angehängte Dateien:

Lesenswert?

Hi,

ich bin gerade dabei mit dem EEprom der Xmega Serie zu experimentieren.
Als Lib nutze ich die modifizierten Atmel Treiber (siehe Anhang), sowie 
Avr Studio 5 mit GCC und das 128A1 Xplained mit Dragon.

Das Testprogramm schreibt die 3 Zahlen: 12, 25000, 4200000 ins EEprom 
und liest sie anschließend wieder aus und sendet das Ausgelesene per 
USART an den PC.

Hier mein Code:
1
#define F_CPU 2000000UL
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include "hardware/usart.h"
6
#include <avr/eeprom.h>
7
#include <stdlib.h>
8
#include <stdio.h>
9
10
11
#include "avr_compiler.h"
12
#include "eeprom_driver.h"
13
14
#define TEST_BYTE_ADDR_1 0x00
15
#define TEST_BYTE_ADDR_2 0x01
16
#define TEST_BYTE_ADDR_3 0x05
17
18
#define TEST_PAGE_ADDR_1    0  /* Page address always on a page boundary. */
19
#define TEST_PAGE_ADDR_2    2  /* Page address always on a page boundary. */
20
21
 
22
volatile unsigned char buf1;
23
volatile unsigned int buf2;
24
volatile unsigned long int buf3;
25
26
void refresh_data(void)
27
{
28
  buf1 = eeprom_read8(TEST_PAGE_ADDR_1, TEST_BYTE_ADDR_1);
29
  buf2 = eeprom_read16(TEST_PAGE_ADDR_2, TEST_BYTE_ADDR_2);
30
  buf3 = eeprom_read32(TEST_PAGE_ADDR_1, TEST_BYTE_ADDR_3);  
31
}
32
33
34
35
int main(void)
36
{
37
  char message[64] = {};
38
  
39
  EEPROM_EnableMapping();
40
  
41
  usartC0_init(9600);
42
  
43
44
  eeprom_write8(TEST_PAGE_ADDR_1, TEST_BYTE_ADDR_1, 12);
45
  eeprom_write16(TEST_PAGE_ADDR_2, TEST_BYTE_ADDR_2, 25000);
46
  eeprom_write32(TEST_PAGE_ADDR_1, TEST_BYTE_ADDR_3, 4200000);
47
48
49
    while(1)
50
    {
51
    _delay_ms(1000);
52
    refresh_data();
53
    sprintf(message, "buf1: %i  buf2: %u  buf3: %lu \r\n", buf1, buf2, buf3);
54
    usartC0_puts(message);
55
    
56
57
    }
58
}

Jetzt zu meinem Problem:

Wenn ich 16- oder 32Bit Variablen auf eine andere Seite als die erste 
schreibe (page != 0x00) dann ist die Speicherzelle leer, wenn ich sie 
wieder lese, das Schreiben (oder das Lesen??) schlägt also fehl. Wenn 
ich hingegen nur 8Bit schreibe, klappt es immer, egal wohin ich das Byte 
schreibe... Hat jemand eine Idee, woran das liegen könnte?


Grüße,
Philip

von Gerhard G. (g_g)


Lesenswert?

Hallo,

#include <avr/eeprom.h>
kann bei den Atxmegas nicht verwendet werden.

#include "eeprom_driver.h"
Du hast doch den richtigen Treiber bereits installiert!

EEPROM_WriteByte(..,..,..); Das ist der richtige Befehl.

Sowas gibt es auch zum Lesen.

Schau dir mal den Treiber eeprom_driver.h/eeprom_driver.c an.
Hier findest du die Befehle die auch funktionieren!

Oder aber auch hier:
Beitrag "Xmega EEPROM"

Gruß G.G.

von Philip P. (nerb)


Lesenswert?

Hallo,

danke für deine Antwort.

das #include "eeprom_driver.h" stammt noch aus einem vorherigen 
Testversuch, wird aber nicht mehr benutzt. Habe bloß vergessen das aus 
dem Code zu streichen.

Ich benutze den Memory Mapped Modus, da funktioniert diese Funktion 
nicht, die ist nur für den IO-Betrieb. Memory Mapped Modus benutze ich 
wegen des leichteren Zugriffs, die Funktionen für 16- und 32Bit Zugriffe 
fallen wesentlich kleiner aus. Umstellen möchte ich eig. nicht, denn es 
kann ja nicht sein, dass das nicht funktioniert...

Den Beitrag kenne ich und auch diesen Beitrag hier: 
Beitrag "xMega EEPROM Memory-mapped"

Leider funktioniert die "xeeprom.h" überhaupt nicht, ich lese immer nur 
0. Echt zum verrückt werden mit dem Xmega ;)


Grüße,
Philip

von Gerhard G. (g_g)


Lesenswert?

Hallo,


Philip P. schrieb:

>> eeprom_write32(TEST_PAGE_ADDR_1, TEST_BYTE_ADDR_3, 4200000);

Wo ist diese Funktion definiert?


Gruß G.G.

von Philip P. (nerb)


Lesenswert?

Hallo,

die ist in der "eeprom_driver.h" bzw "eeprom_driver.c" im Anhang. Die 
Lib habe ich um diese Funktionen erweitert, die sind nicht standardmäßig 
drin.

Grüße,
Philip

von Gerhard G. (g_g)


Lesenswert?

Hallo,

Philip P. schrieb:
> die ist in der "eeprom_driver.h" bzw "eeprom_driver.c" im Anhang. Die
> Lib habe ich um diese Funktionen erweitert, die sind nicht standardmäßig
> drin.

dann zeig sie uns mal.. hier liegt doch dein Problem!


Gruß G.G.

von Philip P. (nerb)


Lesenswert?

Hi,

okay, dann ausgeschrieben:

8bit:
1
#define EEPROM(_pageAddr, _byteAddr) \
2
  ((uint8_t *) MAPPED_EEPROM_START)[_pageAddr*EEPROM_PAGE_SIZE + _byteAddr]
3
4
uint8_t eeprom_read8( uint8_t pageAddr, uint8_t byteAddr )
5
{
6
  EEPROM_WaitForNVM();
7
  return EEPROM(pageAddr, byteAddr);
8
}
9
10
void eeprom_write8( uint8_t pageAddr, uint8_t byteAddr, uint8_t value )
11
{
12
  EEPROM_WaitForNVM();
13
  EEPROM(pageAddr, byteAddr) = value;
14
  EEPROM_AtomicWritePage(pageAddr);
15
}

16bit:
1
#define EEPROM16(_pageAddr, _byteAddr) \
2
  ((uint16_t *) MAPPED_EEPROM_START)[_pageAddr*EEPROM_PAGE_SIZE + _byteAddr]
3
4
uint16_t eeprom_read16( uint8_t pageAddr, uint8_t byteAddr )
5
{
6
  EEPROM_WaitForNVM();
7
  return EEPROM16(pageAddr, byteAddr);
8
}
9
10
void eeprom_write16( uint8_t pageAddr, uint8_t byteAddr, uint16_t value )
11
{
12
  EEPROM_WaitForNVM();
13
  EEPROM16(pageAddr, byteAddr) = value;
14
  EEPROM_AtomicWritePage(pageAddr);
15
}

mit Pageschreibfunktion:
1
void EEPROM_AtomicWritePage( uint8_t pageAddr )
2
{
3
  /* Wait until NVM is not busy. */
4
  EEPROM_WaitForNVM();
5
6
  /* Calculate page address */
7
  uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGE_SIZE);
8
9
  /* Set address. */
10
  NVM.ADDR0 = address & 0xFF;
11
  NVM.ADDR1 = (address >> 8) & 0x1F;
12
  NVM.ADDR2 = 0x00;
13
14
  /* Issue EEPROM Atomic Write (Erase&Write) command. */
15
  NVM.CMD = NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc;
16
  NVM_EXEC();
17
}

Also 8Bit Schreib-/Lesevorgänge gehen auf allen Pages, die 16Bit nur auf 
Page 0. Leider kann ich nicht ganz nachvollziehen, warum das so ist.

Getestet wurde der Code auch auf einem Xmega192A3 (rev.H). Sowohl der 
als auch der Xmega128A1 vom XPlained haben den Hardwarebug:
1
/*EEPROM page buffer always written when NVM DATA0 is written
2
If the EEPROM is memory mapped, writing to NVM DATA0 will corrupt data in the EEPROM page buffer.
3
Problem fix/Workaround
4
Before writing to NVM DATA0, for example when doing software CRC or flash page buffer
5
write, check if EEPROM page buffer active loading flag (EELOAD) is set. Do not write NVM
6
DATA0 when EELOAD is set.*/

Nur schreibe ich nicht auf den Flash, deshalb sollte sich der Fehler 
nicht auswirken. Hat jemand ne Idee?

Grüße,
Philip

von Philip P. (nerb)


Lesenswert?

Hallo,

ich habe jetzt die "Lösung" gefunden:
1
uint16_t eeprom_read16( uint8_t pageAddr, uint8_t byteAddr )
2
{
3
  EEPROM_WaitForNVM();
4
  uint16_t buf;
5
  buf = (uint16_t)EEPROM(pageAddr, byteAddr) << 8;
6
  buf +=(uint16_t)EEPROM(pageAddr, ++byteAddr);
7
  return buf;
8
}
9
10
void eeprom_write16( uint8_t pageAddr, uint8_t byteAddr, uint16_t value )
11
{
12
  EEPROM_WaitForNVM();
13
  EEPROM(pageAddr, byteAddr) = value >> 8;
14
  EEPROM(pageAddr, ++byteAddr) = value;
15
  EEPROM_AtomicWritePage(pageAddr);
16
}

Mit einzelnen 8Bit Zugriffen scheint es also zu funktionieren...
Kann jemand sagen, warumd as so ist?

Grüße,
Philip

von Timmo H. (masterfx)


Lesenswert?

G. G. schrieb:
> Hallo,
>
> #include <avr/eeprom.h>
> kann bei den Atxmegas nicht verwendet werden.
Schwachsinn. Benutze ich schon lange beim Xmega. Klappt wunderbar. Ihr 
solltet mal eure Toolchain updaten.
Warum eine eigenen Treiber schreiben wenn alles schon fertig ist?!
Vorallem ist es dann portabel.

von Philip P. (nerb)


Lesenswert?

Hi,

das wusste ich nicht. Und damit funktioniert es perfekt... Danke!!

Grüße

von Matthias (Gast)


Lesenswert?

Timmo H. schrieb:
>> Hallo,
>>
>> #include <avr/eeprom.h>
>> kann bei den Atxmegas nicht verwendet werden.
> Schwachsinn. Benutze ich schon lange beim Xmega. Klappt wunderbar. Ihr
> solltet mal eure Toolchain updaten.
> Warum eine eigenen Treiber schreiben wenn alles schon fertig ist?!
> Vorallem ist es dann portabel.

Ich würde auch gerne die gewohnten Funktionen aus der eeprom.h für mein 
XMEGA Projekt einsetzen. Allerings bekomme ich vom Compiler unten 
stehende Warnings:

#include <avr/eeprom.h>

#define WERT_LSB 0x00

main()
{
...
 ReadBack = (unsigned int) eeprom_read_byte(WERT_LSB);
...
}

Warnung  1  passing argument 1 of '__eerd_byte_x16a4u' makes pointer 
from integer without a cast [enabled by default]


Meldung  2  expected 'const uint8_t *' but argument is of type 'int'

Bei den Attinys funktionierte das ohne Warnings. AtmelStudio 6.1

Danke für Eure Unterstützung,
Matthias

von Timmo H. (masterfx)


Lesenswert?

Matthias schrieb:
> main()
> {
> ...
>  ReadBack = (unsigned int) eeprom_read_byte(WERT_LSB);
> ...
> }
Versuch mal
1
ReadBack = (unsigned int) eeprom_read_byte((const uint8_t *)WERT_LSB);
Du kannst die Adressen auch von gcc verwalten lassen indem zu EEMEM 
verwendest. Siehe 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#EEMEM

von Matthias (Gast)


Lesenswert?

Timmo H. schrieb:
> ReadBack = (unsigned int) eeprom_read_byte((const uint8_t *)WERT_LSB);

Danke für den typecast Tipp. Die Warnungen sind weg für diese Funktion.

Leider funktioniert der type cast für die eeprom_write_byte nicht. Siehe 
folgende Funktionsaufruf.
1
eeprom_write_byte (WERT_LSB_ADR, (uint8_t) WERT_LSB);

Warning  1  passing argument 1 of '__eewr_byte_x16a4u' makes pointer 
from integer without a cast [enabled by default]
Message  2  expected 'uint8_t *' but argument is of type 'int'

Wenn ich den Funktionsaufruf wie folgt anpasse, dann sind zwar für die 
Funktion auch die Warnungen weg, allerdings funktioniert dann das ganze 
Programm nicht mehr.
1
eeprom_write_byte ((uint8_t *)WERT_LSB_ADR, (uint8_t) WERT_LSB);
Sollte doch eigentlich funktionieren, siehe folgenden 
Funktionsprototypen:
1
void eeprom_write_byte (uint8_t *__p, uint8_t __value);
Übrigens ich im Kapitel 4.7 vom XMEGA A Manual:
The EEPROM supports both byte and page access.

Vielleicht hat ja jemand noch mal einen Tipp für mich.

Danke schon mal im Vorraus,
Matthias

von Timmo H. (masterfx)


Lesenswert?

Wie wärs mit
1
eeprom_write_byte (((uint8_t *)WERT_LSB_ADR, (uint8_t) WERT_LSB);

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.