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

Pamięć FRAM FM25256 - SPI

canion 23 Wrz 2011 08:41 2242 9
  • #1 9954919
    canion
    Poziom 10  
    Witam. Chciałbym zapisywać dane do pamięci FM25256 poprzez interfejs SPI w ATMedze32, następnie je odczytać. Kompiluję w WinAVR (gcc). Korzystałem z kilku przykładów znalezionych na internecie, to co udało mi się zrobić przedstawiam poniżej.
    Testując - zaświecając kolejno diody w funkcji SPI_EEPROM_Write, wstawiając po każdym SPI_Transfer(), PORTA=_BV(0), (1) ITD, funkcja Write dochodzi do końca. Niestety nie mogę odczytać. w SPI_EEPROM_Read nie zapaliła się ani jedna dioda.

    Prosiłbym o pomoc.

    Oto kod:


    Kod: text
    Zaloguj się, aby zobaczyć kod
  • #2 9955545
    kchpl
    Poziom 15  
    Witam,
    Proponuję po adresie do odczytu dołożyć jeszcze jeden SPI_Transfer(0xFF);-żeby dalej podawać zegar do pamięci, ustawić CS i dopiero po tym wyświetlić odebraną daną z SPDR
  • #3 9956388
    canion
    Poziom 10  
    Niestety nic to nie pomogło. Zaświecając kolejno diody po wywołaniach SPI_Transfer() w funkcji SPI_EEPROM_Read(), zauważyłem że program zatrzymuje się na instrukcji read: SPI_Transfer(INSTR_READ); - nie przechodzi dalej. Próbowałem wyświetlić sobie rejestr SPDR na diodach, ale za każdym razem to samo - diody się nie palą, nawet w funkcji SPI_EEPROM_Write(), mimo, że funkcja przechodzi do końca. Więc nie wiem, czy cokolwiek jest zapisane.
  • #4 9958014
    BoskiDialer
    Poziom 34  
    1/ Po co przed odczytem z FRAM'u przełączać SPI w tryb slave? Procesor zawsze jest masterem, wszak on narzuca czy ma występować odczyt czy zapis, on też generuje sygnał zegarowy. To jest przyczyna zatrzymywania się na "SPI_Transfer(INSTR_READ);" - procesor oczekuje na sygnał zegarowy, ale ten nigdy się nie pojawia.
    2/ Funkcje SPI_Set_SS i SPI_Reset_SS są napisane źle, powodując kasowanie bitów, których nie powinny modyfikować.
  • Pomocny post
    #5 9964701
    kchpl
    Poziom 15  
    Witam.
    Wywal zmianę na slava, dodaj jeszcze jeden transfer po adresach w odczycie.
    Proponowałbym tez zmienić funkcję zapisu, potrzebne są tylko dwa op-cody (WREN i WRITE).
    Przyjrzyj się przebiegom na 8 stronie datasheetu.
  • #6 9964970
    canion
    Poziom 10  
    Poniżej zamieszczam poprawiony kod. Funkcje zapisu i odczytu wykonują się, mam natomiast problem, gdyż po porównaniu informacji zapisanej z odczytaną - informacja się różni.



    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <inttypes.h>
    #include <stdlib.h>
    #include <stdint.h>

    #define INSTR_READ 0b00000011
    #define INSTR_WRITE 0b00000010
    #define INSTR_WREN 0b00000110
    #define INSTR_WRDI 0b00000100
    #define INSTR_RDSR 0b00000101
    #define INSTR_WRSR 0b00000001

    int time=0;
    int a=0;

    void delay (int time)
    {
    for(a=0; a<=time; a++)
    {
    _delay_ms(100);
    }

    a=0;
    }

    ////////////////////////SPI ////////////////////


    uint8_t SPI_EEPROM_Read (uint16_t);
    uint8_t SPI_EEPROM_Write (uint16_t, uint8_t);
    uint8_t SPI_Transfer (uint8_t);


    void SPI_Set_SS()
    {
    PORTB &= ~0x10;
    }


    void SPI_Reset_SS()
    {
    PORTB |= 0x10;
    }


    void SPI_Init_Master (void)
    {
    DDRB |= (1<<DDB5)|(1<<DDB7)|(1<<DDB4);
    PORTB |= (1<<PB4);
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPR1);
    }


    uint8_t SPI_Transfer (uint8_t c)
    {
    SPDR= c;
    while (!(SPSR & (1<<SPIF))); //czekaj na koniec transmisji
    return SPDR;

    }


    //////////////////CZYTANIE /////////////////////

    uint8_t SPI_EEPROM_Read(uint16_t Adres)
    {
    SPI_Set_SS(); //start

    _delay_us(0.5);

    SPI_Transfer(INSTR_READ); // opcode read.
    SPI_Transfer (Adres >> 8); // hi adres
    SPI_Transfer (Adres & 0xFF); // lo adres

    SPI_Transfer(0xFF);

    SPI_Reset_SS();

    uint8_t bufor = SPDR;

    return bufor;
    }



    ///////////////////////////ZAPIS ////////////////////

    uint8_t Dane;

    uint8_t SPI_EEPROM_Write(uint16_t Adres, uint8_t Data)
    {
    Dane = Data;

    SPI_Set_SS(); // start Write
    _delay_us(0.5);

    SPI_Transfer(INSTR_WREN);
    SPI_Reset_SS();

    _delay_us(0.5);

    SPI_Set_SS();
    SPI_Transfer(INSTR_WRITE); //opcode write
    SPI_Transfer(Adres >> 8); //adres
    SPI_Transfer(Adres & 0xFF); //adres
    SPI_Transfer(Data);

    _delay_us(0.5);
    SPI_Reset_SS();
    return 0;
    }


    int main(void)
    {
    DDRA=0xFF;
    PORTA=0x00;

    SPI_Init_Master();
    SPI_EEPROM_Write(100, 200); //pod adres 100 zapisz 200

    PORTA|=_BV(0); //zapal diode PA0
    delay(30);

    uint8_t bufor2 = SPI_EEPROM_Read(100);

    PORTA|=_BV(1); //zapal diode PA1
    delay(30);


    if (bufor2 == Dane)
    {
    PORTA|=_BV(2);
    }

    else //jesli sie rozni

    {
    PORTA|=_BV(7);
    }

    while(1)
    {
    }
    }

    Dodano po 9 [minuty]:

    Podglądając SPDR w sposób podany niżej, mam same zera (po odpięciu programatora), z podpiętym programatorem same jedynki:


    int main(void)
    {
    DDRA=0xFF;
    PORTA=0x00;

    SPI_Init_Master();
    SPI_EEPROM_Write(100, 200); //pod adres 100 zapisz 200

    PORTA|=_BV(0); //zapal diode PA0
    delay(30);

    uint8_t bufor2 = SPI_EEPROM_Read(100);

    PORTA|=_BV(1); //zapal diode PA1
    delay(30);

    PORTA=bufor2; //pokaz na porcie A co odczytano

    /*if (bufor2 == Dane)
    {
    PORTA|=_BV(2);
    }

    else

    {
    PORTA|=_BV(7);
    }*/

    while(1)
    { }
    }
  • #7 9965580
    BoskiDialer
    Poziom 34  
    Po pierwsze
    Kod: text
    Zaloguj się, aby zobaczyć kod

    Po drugie zmienna globalna "Dane" ma wartość równą zero, więc jeśli odczytasz wartość 200 i porównujesz do zera, to rzeczywiście dane będą różne. (kod jest tak nieczytelny, że nie zauważyłem przypisania do zmiennej Dane wewnątrz funkcji zapisującej).
  • #8 9965784
    canion
    Poziom 10  
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wyświetlenie rejestru SPDR na porcie A w funkcji SPI_EEPROM_Read() usunąłem, ponieważ wystarczy że sprawdzę zgodność danej zapisanej i odczytanej. Przepraszam za nieczytelność kodu.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Na SPDR wystawia same jedynki, czyli mam rozumieć, że w tym czasie pamięć zacznie wysyłać dane z komórki pamięci poprzez MISO?

    Aktualnie zapala mi się dioda PA7, a więc dane zapisane i odczytane się różnią.
  • Pomocny post
    #9 9965833
    BoskiDialer
    Poziom 34  
    Ostatnia rzecz jaka przychodzi mi do głowy, to zabezpieczenie pamięci przed zapisem. Do odbezpieczenia może być konieczne ustawienie pinu WP w stan wysoki, po czym zapisanie do rejestru statusu (instrukcja WRSR) wartości 0x00 (cała pamięć odbezpieczona, brak zabezpieczenia rejestru statusu pinem WP) [zapis musi być poprzedzony przez WREN].

    Innych firmwareowych źródeł problemu już raczej nie widzę, w szczególności że wiem jak przyjemna jest ta pamięć - ostatnio uruchamiałem FM25L256B z procesorem stm32 i działało od pierwszego użycia.

    Jeśli i to nie pomoże, możesz zacząć sprawdzanie, czy SPI działa poprawnie:
    - wymusić CS w stan wysoki (ważne aby nie wystąpił konflikt pomiędzy dwoma nadajnikami), zrobić obejście pomiędzy miso i mosi, wtedy wartość uzyskana z SPI_Transfer będzie równa tej wysłanej, np: SPI_Transfer(0xA5) gdy SPI będzie działać, zwróci wartość 0xA5. Po tym teście usunąć obejście mosi-miso.
    - następne, to próba odczytania rejestru statusu z tej pamięci, powinno dawać wartości różne od 0xFF, jako że 4 bity są sprzętowo wymuszone do bycia równymi zero. Jeśli odczytana wartość jest równa 0, to przy okazji wiadomo, że pamięć właściwa nie jest zabezpieczona przed zapisem.
  • #10 9967979
    canion
    Poziom 10  
    Dzięki wielkie za pomoc. Pamięć była zabezpieczona. Problem rozwiązany. Zamykam temat.
REKLAMA