LinkedIn YouTube Facebook
Szukaj

Wstecz
Artykuły

Komunikacja mikrokontrolerów STM32 z pamięciami DataFlash

Zapis do bufora

Pamięć AT45DB321D ma wbudowane dwa bufory SRAM o rozmiarze 528/512 bajtów każdy. Poniżej przedstawiono sposób zapisu danych do jednego z nich. Zapis rozpoczyna się od wysłania do układu pamięci odpowiedniego rozkazu, dla pierwszego bufora będzie to kod 0x84, a dla drugiego 0x87. Po kodzie rozkazu mikrokontroler powinien wysłać trzy bajty adresowe, które, jeśli zinterpretować je jako jeden ciąg bitów, zawierają na początku 14 bitów nieznaczących, a następnie 10 bitów identyfikujących bajt, od którego będzie następował zapis bufora. Po bajtach adresowych można już przesyłać dane przeznaczone do zapisu do bufora. Dane będą zapisywane do czasu, aż na linii chip select (CS) nie pojawi się zbocze narastające. Warto również zaznaczyć, że po osiągnięciu końca bufora, tj, po zapisie jego ostatniego bajta, proces rozpoczyna się od początku bufora. Nieco więcej światła na przedstawioną wyżej komunikację z pewnością rzuci rysunek 10.

 

Rys. 10. Zapis do bufora SRAM pamięci AT45DB321D

Rys. 10. Zapis do bufora SRAM pamięci AT45DB321D

 

 

List. 8. Ciało funkcji zapisującej bufor SRAM pamięci zewnętrznej

void writeBuffer(uint16_t address, uint16_t nofBytesToWrite)
{
    /* sprawdzanie muteksa */
    while(SPI_InUse);
    /* "weź" muteks */
    SPI_InUse = 0x11;
    SPI_Cmd(SPI1, DISABLE);
    SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);
    SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_TXE, ENABLE);
    /* pierwszy bajt to komenda, następne trzy to bajty adresu */
    Nof_Bytes_To_TxRx = 4 + nofBytesToWrite;
    /* Komenda "write to buffer 0" */
    TxBuf[0] = 0x84;
    /* Starsze 2 bity adresu bajta w buforze */
    TxBuf[2] = (uint8_t) address>>8;
    /* Pozostałe 8 bitów adresu */
    TxBuf[3] = (uint8_t) address;
    SPI_Cmd(SPI1, ENABLE);
    GPIO_SetBits(GPIOA, CS);
    /* CS w stan niski */
    GPIO_ResetBits(GPIOA, CS);
}

 

Funkcję realizującą zapis do bufora przedstawiono na listingu 8. W argumentach do funkcji należy przesłać rozkaz, do którego bufora zapis ma być przeprowadzony (0x84 lub 0x87) oraz liczbę zapisywanych bajtów. Globalny bufor nadawczy musi być wypełniony przez wywołaniem funkcji wysyłające dane dla bufora. Podobnie, jak było poprzednio, również funkcja bufferWrite(), zabiera muteks dla kontrolera SPI, blokując w ten sposób dostęp do kontrolera SPI. Jeśli dalej w programie zaistnieje potrzeba skorzystania z SPI, to w pierwszej kolejności należy sprawdzić, czy muteks został oddany, co będzie jednoznaczne z tym, że kontroler SPI jest gotowy do ponownego użycia.

Zapis bufora do pamięci

Gdy żądane operacje zapisu do bufora zostaną już przeprowadzone, należałoby jego zawartość zapisać do pamięci nieulotnej. Możliwe są dwa sposoby zapisu. Pierwszy polega na zapisie zawartości bufora bez kasowania docelowej strony w pamięci, natomiast drugi najpierw wymaże zawartość strony, a dopiero po tym wykonany będzie zapis danych z bufora. Przedstawimy ten drugi sposób.
Komenda zapisu bufora do pamięci to odpowiednio na bufora 1 i bufora 2: 0x83 oraz 0x86. Po kodzie komendy muszą zostać wysłane trzy bajty adresowe, określające, która strona w pamięci będzie zapisywana. Trzynaście bitów adresowych powinno być rozmieszczone w wysyłanych bajtach analogicznie do adresowania strony przeznaczonej do skasowania (patrz rysunek 7).

 

List. 9. Funkcja wyzwalająca zapis bufora do pamięci nieulotnej

void writeBuffer2Memory(uint16_t address)
{
    /* sprawdzanie muteksa */
    while(SPI_InUse);
    /* "weź" muteks */
    SPI_InUse = 0x11;
    SPI_Cmd(SPI1, DISABLE);
    SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);
    SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_TXE, ENABLE);
    /* pierwszy bajt to komenda, trzy pozostałe to bajty adresu */
    Nof_Bytes_To_TxRx = 4;
    /* Komenda "write buffer to memory" */
    TxBuf[0] = 0x83;
    /* Starsze 7 bitów adresu strony */
    TxBuf[1] = (uint8_t) address>>6;
    /* Pozostałe (młodsze) 6 bitów adresu strony,
     * ale wyrównane do lewej strony */
    TxBuf[2] = (uint8_t) address<<2;
    SPI_Cmd(SPI1, ENABLE);
    GPIO_SetBits(GPIOA, CS);
    /* CS w stan niski */
    GPIO_ResetBits(GPIOA, CS);

    /* Oczekiwanie na zakończenie wysyłania komendy i adresu strony */
    while(SPI_InUse);
    /* ponownie "weź" muteks */
    SPI_InUse = 0x11;

    /* SysTick bedzie taktowany z f = 72MHz/8 = 9MHz.
     * Przerwanie ma byc po 40 ms, f = 9MHz, czyli liczy od 360000 - 1 */
    SysTick->LOAD  =  360000 - 1;
    /* Włączenie przerwania od timera SysTick */
    NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
    /* Zerowanie aktualnej wartości licznika */
    SysTick->VAL  = (0x00);
    /* Wypełnienie rejestru kontrolnego timera SysTick:
     * -SYSTICK_CLKSOURCE - bit 2, 0 - HCLK/8, 1 - HCLK
     * -SYSTICK_TICKINT - bit 1, włączenie przerwania od timera
     * -SYSTICK_ENABLE - bit 0, włączenie timera */
    SysTick->CTRL = (0<

 

Kasowanie, a następnie zapisywanie strony rozpoczyna się po wystąpieniu narastającego zbocza na linii CS. Podobnie, jak miało to miejsce w przypadku kasowania strony, czas wymagany, na wykonie całej operacji nie jest krótki i może wynosić od 17, do 40 ms. Problem oczekiwania na zakończenie operacji kasowania i programowania strony rozwiązano w takim sam sposób, jak przy poleceniu kasowania strony. Do odmierzania czasu użyty został systemowy timer SysTick. Ciało funkcji zapisującej bufor do pamięci przedstawiono na listingu 9. Jest to kod analogiczny, do funkcji kasowania strony, różnica, to oczywiście wartość pierwszego bajta (czyli komendy rozkazu), pozostały schemat komunikacji jest taki sam. Jedynie timer SysTick jest konfigurowany do wygenerowania przerwania po upływie dłuższego czasu – po 40 ms.