Skocz do zawartości

Obsługa tablicy Flash <-> RAM


Pawel88

Pomocna odpowiedź

Witam,

Zaczynam amatorsko przygodę z STM32F103C8T6 i przepraszam za ewentualne amatorskie pytania 😉

Chcę w programie obsługiwać dużą tablicę dwuwymiarową:

int8_t tablica[500][16];

Jest ona umieszczona w RAM, a także umieszczona pod koniec pamięci FLASH STM32 w celu przepisania do RAM po włączeniu zasilania.

Tablica będzie też przesyłana przez USART do PC.

Wstępnie mam taki kod do zapisu:

	FLASH->KEYR = FLASH_KEY1;
	FLASH->KEYR = FLASH_KEY2;
	//FLASH_Erase Page
	while((FLASH->SR&FLASH_SR_BSY));
	FLASH->CR |= FLASH_CR_PER; //Page Erase Set
	FLASH->AR = 0x0801FC00; //Page Address
	FLASH->CR |= FLASH_CR_STRT; //Start Page Erase
	while((FLASH->SR&FLASH_SR_BSY));
	FLASH->CR &= ~FLASH_CR_PER; //Page Erase Clear
	FLASH->CR |= FLASH_CR_PG;

	uint16_t i;
	uint16_t d;
	for(i=0; i<15; i++){
		while((FLASH->SR&FLASH_SR_BSY));
		d=(uint16_t)(((tablica[0][i+1])<<8) + tablica[0][i]);
		*(__IO uint16_t*)(0x0801FC00 + i) = d;
	}

	FLASH->CR &= ~FLASH_CR_PG;
	FLASH->CR |= FLASH_CR_LOCK;

1. Czym są FLASH_KEY1 i FLASH_KEY2?

2. Jak sensowniej obsłużyć przepisanie danych tablicy? Zakładam, że chyba lepiej przez wskaźniki, ale dopiero się uczę i nie jestem pewny jak to zrobić.

 

Pozdrawiam.

Edytowano przez Pawel88
Link do komentarza
Share on other sites

@Pawel88 Zadając pytanie o STM32 warto chociaż raz wspomnieć o którym modelu mikrokontrolera piszesz. Bo pytać o stm32 to jakby napisać, że masz problem z samochodem, ale bez podawania modelu.

Druga sprawa, to może napisz skąd masz ten kod - bo jak rozumieć pytanie:

6 minut temu, Pawel88 napisał:

1. Czym są FLASH_KEY1 i FLASH_KEY2?

Napisałeś program i nie wiesz jak?

Link do komentarza
Share on other sites

Proponuję wrócić do dokumentacji: https://www.st.com/content/ccc/resource/technical/document/programming_manual/10/98/e8/d4/2b/51/4b/f5/CD00283419.pdf/files/CD00283419.pdf/jcr:content/translations/en.CD00283419.pdf

Kody z internetu nie zawsze działają, ale nawet jeśli tak to warto zrozumieć o co w tym wszystkim chodzi.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Ale ja już wcześniej wpisałem do tych rejestrów:

#define FLASH_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)

Tylko nie wiem, skąd biorą się te wartości. Ale pomińmy te pytanie, bo będę odsyłany do dokumentacji, które już oglądałem 🙂

 

Jak zapisać obsługę tej tablicy przez wskaźniki? Ponieważ są tu też różne wielkości zmiennych.

Link do komentarza
Share on other sites

A zaglądałeś do dokumentu który podlinkowałem? Na stronie 12 (podpunkt 2.3.1) są te wartości wymienione.

Ich wartości nie mają jakiegoś szczególnego znaczenia. Jest to zabezpieczenie przed błędem w programie - inaczej program mógłby skasować lub nadpisać pamięć Flash przez przypadek. Natomiast błąd w programie, który akurat do rejestru KEYR wpisze oczekiwaną wartość jest znacznie mniej prawdopodobny. Jakby co to wszystko masz we wspomnianej dokumentacji - podpunkt 2.3.2 tym razem.

A co do drugiego pytania - to może najpierw sprawdź, czy to co masz działa poprawnie. Ulepszanie kodu to dobry pomysł, ale może najpierw lepiej się upewnić, że to co mamy działa.

Stąd moje pytanie: czy program działa? I pytanie pomocnicze -  jak to testujesz?

  • Lubię! 2
Link do komentarza
Share on other sites

No, OK. Przecież mówiłem, że zaglądałem, ale nie znalazłem sensu tych wartości. Czyli to przypadkowe liczby które wymyślił sobie producent 😉

Ale jak już wspomniałem tematem jest obsługa tablicy Flash / RAM.

Więc jeszcze raz zapytam, Jak zapisać obsługę tej tablicy przez wskaźniki dla różnych wielkości zmiennych?

Proszę tylko o pomoc na ten temat.

Link do komentarza
Share on other sites

Napisałem wcześniej, ale wiadomości się połączyły, więc powtórzę - zacznij od poprawienia i przetestowania programu, który napisałeś. Używanie wskaźników to dobry pomysł, ale program napisany w takim stylu jak teraz też powinien działać. Jako ułatwienie podpowiem:

	for(i=0; i<15; i++){
		d=(uint16_t)(((tablica[0][i+1])<<8) + tablica[0][i]);

Teraz zadanie dla Ciebie - gdzie tu jest błąd?

 

A co do wskaźników, to wystarczy brutalnie rzutować to co masz w tablicy, czyli uint8_t na uint16_t - procesor używa trybu little-endian, więc liczby 16 bitowe będą interpretowane tak jak powinno działać przypisanie do d.

Link do komentarza
Share on other sites

Pisałem kod na szybko, więc trochę offset na tablicy przesunięty 😉

 

W międzyczasie pojawiło mi się pytanie: Czy trzeba przepisywać tablicę z Flash do RAM, czy podczas startu procesora jest to robione automatycznie?

Link do komentarza
Share on other sites

Wszystko zależy co chcesz uzyskać. Najprościej jest zamienić dane na kod w C i skompilować wraz z resztą programu - w sieci znajdziesz gotowe skrypty które to robią.

Jeśli tablica będzie zadeklarowana jako stała, to zostanie umieszczona w pamięci Flash i nie będziesz mógł jej modyfikować. Natomiast zadeklarowanie jej jako zmiennej z początkową wartością daje dokładnie to co próbujesz zrobić. Wartości początkowe zostaną zapisane w pamięci Flash i przepisane do RAM przed wejściem do funkcji main.

Link do komentarza
Share on other sites

(edytowany)

Tylko chyba przy deklaracji tablicy jako zmiennej z początkowymi wartościami, nie będę mógł jej zapisywać na stałe i po uruchomieniu procesora mieć nowe dane jakie zapisałem przed wyłączeniem?

 

Chyba żeby jakoś zmusić kompilator, aby zapisywał pod koniec Flash w ściśle określonym miejscu i tam z poziomu programu modyfikować ją.

Edytowano przez Pawel88
Link do komentarza
Share on other sites

(edytowany)

OK, to przejdę do kodu.

Czy tak można wykorzystać wskaźnik?:

for(i=0; i<1023; i++){
  *(__IO uint16_t*)(Page_127 + i) = *(tablica + i);
  {

gdzie: int8_t tablica[500][16];

Edytowano przez Pawel88
Link do komentarza
Share on other sites

Nie, tak nie można. Jednak radziłbym wrócić do pierwszej wersji, wydaje mi się że rozumiałeś ją trochę lepiej, więc poprawienie kodu byłoby dobrym ćwiczeniem.

W tej wersji wszystko jest źle. Zaczynając od tego że po lewej stronie jest wartość 16-bitowa, a po prawej 8-bitowa, kończąc na innym kroku indeksowania - to było źle w pierwszym kodzie i dlatego chciałem żebyś spędził nad nim trochę czasu.

Z drugiej strony nie mam już siły. Proponuję więc zrobić tak:

uint16_t *tablica16 = (uint16_t*)&tablica[0][0]

Teraz możesz używać tablica16 do zapisywania / odczytywania danych z pamięci, masz po obu stronach taki sam typ (uint16_t), nie ma 2 wymiarów, więc same plusy.

Link do komentarza
Share on other sites

Czy taki zapis też jest poprawny?

uint16_t *tablica16 = (uint16_t*)&tablica

 

PS: Co do tej prostej wersji bez wskaźników, to napisałem żartobliwie wyżej, że "trochę offset na tablicy przesunięty". A dokładniej to trzeba było indeksować co 2 a nie co 1 jak w tamtym kodzie.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.