logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

odczyt zapis do flash powyżej 64kB

petroTM 18 Mar 2010 11:57 2731 21
  • #1 7846579
    petroTM
    Poziom 11  
    Mam problem. Potrzebuję zapisać tablicę o rozmiarze 96kB do Flasha. Następnie potrzebuję z niej czytać. Część pierwszą mam zrobioną. Problem pojawia się przy czytaniu z flasha.
    Zapis wyglada tak:

    unsigned char tab1[24413] PROGMEM =
    {...dane...}
    unsigned char tab2[24413] PROGMEM =
    {...dane...}
    unsigned char tab3[24413] PROGMEM =
    {...dane...}
    unsigned char tab4[24413] PROGMEM =
    {...dane...}

    Zeby dokonac odczytu zapewne musze zdefiniowac sekcje itp. Moze ktos poradzic jak to sie robi itp?
    Pozdrawiam
  • #3 7846868
    petroTM
    Poziom 11  
    Ok. Przyjmuje. Natomiast ja chce swoje cztery tablice w sumie zajmujace 96kB wrzucic poza obszar standardowy we flashu tzn za 64kB. W ten sposob omine zabawe w liczenie czy juz uzyc pgm_read_byte czy juz pgm_read_byte_far. Nie potrzebuje operowac na wordach, bo po bajtach zczytuje. Chodzi mi glownie o konstrukcje sekcji. Jak to sie dokladnie deklaruje itp. Wtedy wszystkie tablice umiescilbym w sekcji a do sekcji przypisal adres na 64001(dziesietnie).
  • #4 7846923
    tmf
    VIP Zasłużony dla elektroda
    Jesli interesuje cie odczytanie danych bajtowych to to makro zamieniasz na pgm_read_byte_far i juz. Z sekcjami nic nie musisz kombinowac, po prostu uzywaj wskaznika 32-bitowego. Przeciez to tak samo dobrze zadziala na danych umieszczonych <64kB granicy. Jesli zadeklarujesz inne sekcje to nie zapomnij tez o odpowiedniej modyfikacji makefile, tak, zeby i linker wiedzial co z twoja sekcja zrobic.
  • #5 7846964
    petroTM
    Poziom 11  
    OK. To moze tak:

    
    #include <avr/io.h>
    #include <avr/pgmspace.h>
    #include "tab.h"
    
    char wysylaj = 0xAA;
    uint8_t i = 0;
    uint32_t j = 0;
    uint8_t  licznik = 1;
    
    void SPI_MasterInit(void)		//inicjalizacja SPI
    {
    	/* Set MOSI and SCK output, all others input */
    	DDRB = (1<<DDB2)|(1<<DDB1);
    	/* Enable SPI, Master, set clock rate fck/16 */
    	SPCR = (1<<SPE)|(1<<DORD)|(1<<MSTR)|(1<<CPOL)|(1<<SPR0);
    	
    }
    
    void SPI_MasterTransmit(char cData)		//wysylanie kolejnych bajtow
    {
    	/* Start transmission */
    	SPDR = cData;
    	/* Wait for transmission complete */
    	while(!(SPSR & (1<<SPIF)))
    }
    
    int main()
    {	
    	cli();
    	DDRF = 0b11000000;
    	DDRE = 0xFF;
    	PRR0 = 0x00;
    	SPI_MasterInit();
    	sei();
    	for(j=1;j<=97652;j++)
    	{					
    		if(licznik == 1)
    		{
    			wysylaj = pgm_read_byte_far(&(tab1[i]));
    
    		}
    
    		if(licznik == 2)
    		{
    			wysylaj = pgm_read_byte_far(&(tab2[i]));
    		}
    
    		if(licznik == 3)
    		{
    			wysylaj = pgm_read_byte_far(&(tab3[i]));
    		}
    
    		if(licznik == 4)
    		{
    			wysylaj = pgm_read_byte_far(&(tab4[i]));
    		}
    							
    		if(i>=24412)
    		{
    		   i=0;
    		   licznik++;
    	    }		
    		i++;
    		SPI_MasterTransmit(wysylaj);
    	}
    }
    


    w pliku tab.h sa cztery tablice

    unsigned char tab1[24413] PROGMEM =
    {...dane...}
    unsigned char tab2[24413] PROGMEM =
    {...dane...}
    unsigned char tab3[24413] PROGMEM =
    {...dane...}
    unsigned char tab4[24413] PROGMEM =
    {...dane...} 


    I w tym momencie dane zawarte w tablicach leca na spi? Bo ich wylapac nie moge.. Byc moze zle odbieram.. Bajty powinny byc ulokowane gdzies we flashu i powinny byc wysylane po kolei z kolejnych tabeli przez spi. W kazdym razie, czy kod powyzszy powinien juz zadzialac?
  • #6 7847010
    tadzik85
    Poziom 38  
    Czemu parametrem pętli for jest j a w wewnątrz używasz i?? I dlaczego takie duża wartość ograniczenia, zrób to w 2 pętlach for, a tablice stwórz 2 -wymiarową.
  • #7 7847041
    petroTM
    Poziom 11  
    Ale to co piszesz nie jest do tematu. Zrobilem tak i tyle. Rownie dobrze moglem rozbic na cztery petle. Chodzi o samo zapisywanie do flasha i czytanie z niego. Program przegladam debuggerem i niby dziala, na oscyoskopie tez niby widac ramki ale nie wiem (co tam leci). A uklad, ktory odbiera ramki sie nie programuje.
  • #8 7847070
    tadzik85
    Poziom 38  
    Tak?? To człowieku zacznij myśleć. Jak masz zwiększyć indeks tablic i skoro pętla ma parametr i??. A z Flasha tylko się odczytuje !!!! Sorki widzę ze masz i++ w środku pętli w takim razie po co w ten sposób zadeklarowana pętla FOR??
  • #10 7847090
    tadzik85
    Poziom 38  
    Zauważyłem. Poza tym użyj funkcji po prostu pgm_read_byte(); Kompilator sam dobierze odpowiednia wersje.
  • #11 7847108
    petroTM
    Poziom 11  
    Dlatego, ze w sumie mam 97652 bajtow do wyslania. W ten sposob mam jedna petle i wiele ifow. Nie jest to na pewno najszybsze, ale tak akurat zadeklarowalem. Na pewno w ponizszy sposob bedzie szybciej, bo nie ma warunkow:
    
    	for(j=0;j<24413;j++)
    	{
    		wysylaj = pgm_read_byte_far(&(tab1[j]));
    		SPI_MasterTransmit(wysylaj);
    	}
    	
    	for(j=0;j<24413;j++)
    	{
    		wysylaj = pgm_read_byte_far(&(tab2[j]));
    		SPI_MasterTransmit(wysylaj);
    	}	
    
    	for(j=0;j<24413;j++)
    	{
    		wysylaj = pgm_read_byte_far(&(tab3[j]));
    		SPI_MasterTransmit(wysylaj);
    	}	
    
    	for(j=0;j<24413;j++)
    	{
    		wysylaj = pgm_read_byte_far(&(tab4[j]));
    		SPI_MasterTransmit(wysylaj);
    	}
    


    PS. Dalej nie wiem co jest. Niby wysyla, tak przynajmniej wynika z procesu debugowania. Moze zle odbieram
  • #12 7847129
    tadzik85
    Poziom 38  
    Wywal to "FAR" !! Te tablice zapewne tworzone są zaraz na początku pamięci flash. Tak było u mnie. Kompilator sam dopierze długość adresu. Po co go męczyć arytmetyka na 4 bajtach skoro równie dobrze możne to zrobić na 2?? A dla poprawności politycznej zmień zmienna wysyłaj na bez znaku, tak samo argument funkcji wysyłania przez SPI.

    Teraz kod wygląda poprawnie. Reszta wynikać może jedynie z odbierania przez SPI lub wysyłanie przez niego, jeszcze go nie testowałem wiec trudno mi cie zweryfikować.
  • #13 7847580
    tmf
    VIP Zasłużony dla elektroda
    Tadzik, moze warto cos sprawdzic zanim sie komus poradzi. Zagladajac do pgmspace.h znajdziesz:
    #define pgm_read_byte(address_short) pgm_read_byte_near(address_short)

    Czyli w zaden sposob to makro bez suffiksu _far nie moze dostac sie do danych powyzej 64kB. Inna sprawa, ze kompilator nie mialby jak taki fakt wykryc.

    Tu jest jeszcze problem pobierania adresu czegos umieszczonego powyzej granicy 64kB. Nie da sie tego zrobic za pomoca operatora "&", musisz skorzystac z biblioteki Carlosa Lamasa, w ktorej jest definicja GET_FAR_ADDRESS sluzacego do tego celu.
    Wyglada tak:
    
    #define GET_FAR_ADDRESS(var)                          \
    ({                                                    \
        uint_farptr_t tmp;                                \
                                                          \
        __asm__ __volatile__(                             \
                                                          \
                "ldi    %A0, lo8(%1)"           "\n\t"    \
                "ldi    %B0, hi8(%1)"           "\n\t"    \
                "ldi    %C0, hh8(%1)"           "\n\t"    \
                "clr    %D0"                    "\n\t"    \
            :                                             \
                "=d" (tmp)                                \
            :                                             \
                "p"  (&(var))                             \
        );                                                \
        tmp;                                              \
    })
  • #14 7847694
    tadzik85
    Poziom 38  
    Dobra mój błąd niech zostawi FAR. Puki co nie wykorzystywałem procesora z > 64kB.
    A z pobieżnego przeglądu pliku pgmspace.h wywnioskowałem, że kompilator sam dobiera odpowiednia funkcję. Dobrze wiedzieć, że jednak nie. Ale przy tak wielkich stałych tablicach, ja jednak wykorzystał bym zewnętrzny EEPROM. To tylko moje skromne zdanie.
  • #15 7847705
    Freddie Chopin
    Specjalista - Mikrokontrolery
    tadzik85 napisał:
    Ale przy tak wielkich stałych tablicach, ja jednak wykorzystał bym zewnętrzny EEPROM. To tylko moje skromne zdanie.

    Damn, dobrze że nie zewnętrzne płatne konto na Rapidshare przez http, bo przecież 96kB to jest tak strrrrrrasznie dużo.

    4\/3!!
  • #16 7847723
    Konto nie istnieje
    Poziom 1  
  • #17 7850603
    petroTM
    Poziom 11  
    tmf napisał:
    Tu jest jeszcze problem pobierania adresu czegos umieszczonego powyzej granicy 64kB. Nie da sie tego zrobic za pomoca operatora "&", musisz skorzystac z biblioteki Carlosa Lamasa, w ktorej jest definicja GET_FAR_ADDRESS sluzacego do tego celu.


    Dlaczego nie można tego zrobić za pomocą operatora &? Jak w takim razie mam tę tablicę umieścić, bo przecież część danych będzie we flashu poniżej 64kB, a część powyżej. Czy mogę tę bibliotekę zastosować do zarówno krótkich jak i długich adresów(tzn powyżej 64kB)?

    Dodano po 41 [minuty]:

    Witam. Zamieniłem odczyt w kodzie z
    byte = pgm_read_byte_far(&(tab1[i]));
    na
    byte = pgm_read_byte_far(0x10000UL + (uint32_t) (uint16_t) (tab1[i]));
    W sumie wygląda to tak:
    	for(j=0;j<24413;j++)
    	{
    
    		//byte = pgm_read_byte_far(&(tab1[i]));
    		byte = pgm_read_byte_far(0x10000UL + (uint32_t) (uint16_t) (tab1[i]));
    		SPI_MasterTransmit(byte);
    	}
    	
    	for(j=0;j<24413;j++)
    	{
    		//byte = pgm_read_byte_far(&(tab2[i]));
    	byte = pgm_read_byte_far(0x10000UL + (uint32_t) (uint16_t) (tab2[i]));
    		SPI_MasterTransmit(byte);
    	}	
    
    	for(j=0;j<24413;j++)
    	{
    		//byte = pgm_read_byte_far(&(tab3[i]));
    		byte = pgm_read_byte_far(0x10000UL + (uint32_t) (uint16_t) (tab3[i]));
    		SPI_MasterTransmit(byte);
    	}	
    
    	for(j=0;j<24413;j++)
    	{
    		//byte = pgm_read_byte_far(&(tab4[i]));
    		byte = pgm_read_byte_far(0x10000UL + (uint32_t) (uint16_t) (tab4[i]));
    		SPI_MasterTransmit(byte);
    	}

    W przypadku zastosowania
    #define GET_FAR_ADDRESS(var)                          \
    ({                                                    \
        uint32_t tmp;                                \
                                                          \
        __asm__ __volatile__(                             \
                                                          \
                "ldi    %A0, lo8(%1)"           "\n\t"    \
                "ldi    %B0, hi8(%1)"           "\n\t"    \
                "ldi    %C0, hh8(%1)"           "\n\t"    \
                "clr    %D0"                    "\n\t"    \
            :                                             \
                "=d" (tmp)                                \
            :                                             \
                "p"  (&(var))                             \
        );                                                \
        tmp;                                              \
    
    .
    .jakis kod
    .
    uint32_t adres = 0;
    .
    .jakis kod
    .
    
    adres = GET_FAR_ADDRESS(tab1[i]);
    })

    wyrzuca mi błąd : C:\Documents and Settings\Piotrek\Moje dokumenty\loader\default/../main.c:97: undefined reference to `r28'


    Nie znam assemblera na avrki(zaczynam tego powoli żałować) i nie wiem co ten błąd oznacza. Może ktoś wie?
    Mam jeszcze jedno pytanie. Ponieważ adres powyzej 64kB jest 24 bitowy? to odczytuje ten powyzszy kod assemblerowy odczytuje najpierw mlodsze 8 bitow potem starsze 8 bitow a potem jeszcze jakis 8 bitow i to jest adres? Czy moge uzyc tego
    byte = pgm_read_byte_far(0x10000UL + (uint32_t) (uint16_t) (tab1[i]));
    lub tego GET_FAR_ADRESS do całej pamieci flash czy tylko powyzej 64kB? Domyslam sie, ze nie za bardzo wiec moze ktos wie jak wrzucic cala tablice pod adres we flashu powyzej 64kB?
  • #18 7850894
    tmf
    VIP Zasłużony dla elektroda
    Mozesz uzyc tego do calej przestrzeni adresowej. Jak sie domyslasz dla adresow <64kB po prostu najstarsze 8 bitow bedzie rowne 0. Operatora "&" uzyc nie mozesz bo zwraca on adres tylko 16-bitowy, bo tylko takie wskazniki obsluguje avr-gcc. Najlepiej sciagnij po prostu biblioteke Carlosa. Mozna to jeszcze ominac prosciej - stworzyc nazwana sekcje i w skrypcie linkera umiescic jej poczatek. Wtedy do danych bedziesz mogl sie odwolywac po prostu podajac adres poczatkowy sekcji w ktorej te dane sa. W takim wypadku nie jest ci potrzebna zadna funkcja zwracajaca adres - to chyba bedzie najprostsze rozwiazanie.
  • #19 7850925
    petroTM
    Poziom 11  
    a mozesz przykladowy kod umiescic z zastosowaniem sekcji, tzn jak to umiescic?Czy to bedzie cos w rodzaju jak ponizej?
    #define PROGMEM __attribute__((section(".progmem_global")))
    o dodanie do linkera to masz na mysli "custom operation options" w "edit configuration options". nie wiem, bo nigdy nic nie dodawalem do linkera.
  • Pomocny post
    #20 7851056
    tmf
    VIP Zasłużony dla elektroda
    Jesli korzystasz z AVR Studio to w opcjach projektu mozesz dodawac swoje sekcje podajac ich adres startu i ew. dlugosc. Oczywiscie musisz je nazwac inaczej niz PROGMEM, bo ta nazwa jest juz zajeta. Jesli nie to przekazujesz parametry dla linkera przy wywolaniu gcc, tu jest howto:
    http://www.nongnu.org/avr-libc/user-manual/mem_sections.html
  • #21 7851266
    petroTM
    Poziom 11  
    Zrobiłem coś takiego:

    #define EXTMEM1 __attribute__((section("moja_sekcja1")))
    #define EXTMEM2 __attribute__((section("moja_sekcja2")))
    #define EXTMEM3 __attribute__((section("moja_sekcja3")))
    #define EXTMEM4 __attribute__((section("moja_sekcja4")))


    W opcjach linkera dodałem to
    -Wl,-section-start=moja_sekcja1=0x802200
    -W2,-section-start=moja_sekcja2=0x80815D
    -W3,-section-start=moja_sekcja3=0x80E0BA
    -W4,-section-start=moja_sekcja4=0x814017


    tablice podeklarowalem w ten sposob:
    uint8_t tab1[24413] EXTMEM1=
     {..dane..}
    uint8_t tab2[24413] EXTMEM2=
     {..dane..}
    uint8_t tab3[24413] EXTMEM3=
     {..dane..}
    uint8_t tab4[24413] EXTMEM4=
     {..dane..}
    


    Probuje narazie zczyac pierwszy bajt:
    byte = pgm_read_byte(tab1);


    Adresy w moim procku sa takie:
    Name             Origin             Length             Attributes
    text             0x00000000         0x00100000         xr
    data             0x00800200         0x0000fe00         rw !x
    eeprom           0x00810000         0x00010000         rw !x
    fuse             0x00820000         0x00000400         rw !x
    lock             0x00830000         0x00000400         rw !x
    signature        0x00840000         0x00000400         rw !x
    *default*        0x00000000         0xffffffff
    

    Problem polega na tym, ze teraz linker krzyczy, ze nadpisuje adresy poza obszarem danych tzn: region data overflowed by 8242 bytes.
    Jak sobie poradzic z tym problemem?
  • #22 7851351
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Dziwi Cię to, skoro swoimi adresami trafiasz w (nieistniejący) obszar RAMu? (tak BTW to takie adresy to wymysł kompilatora, fizycznie nie istnieją w ogóle takie obszary w tym układzie)

    Pozatym ile razy pisane było w tym temacie, że pgm_read_...() zadziała TYLKO dla adresu 16-bitowego, a ty tam pakujesz coś spod adresu 0x802200... 16-bitów jak nic...

    Najpierw pomyśl, przeczytaj ten temat raz jeszcze, a potem zrób to dobrze, bo tak mieszasz, że to jest straszne...

    4\/3!!
REKLAMA