Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[AT91SAM7S256][C/Rowley Crossworks] Trzeszczący dźwięk z MP3

Tytus Kosiarski 14 Paź 2009 00:22 13914 103
  • #61 14 Paź 2009 00:22
    atom1477
    Poziom 43  

    No to dziwne. A jak sprawdzasz zajętość karty?

    Ja mam to zrobione tak:

    Code:

    Send_sector_to_sd()
    {
        Send_command_to_sd(0x58);
        Send_command_to_sd(0xFF);

        Spi_send_receive_byte_sd(0xFF);
        Spi_send_receive_byte_sd(0xFF);
        Spi_send_receive_byte_sd(0xFE);


        for (i=0;i<512;i++)
          {
            Spi_send_receive_byte_sd(*Wsk++);
          }


        Spi_send_receive_byte_sd(0xFF);
        Spi_send_receive_byte_sd(0xFF);

        Spi_send_receive_byte_sd(0xFF);




        for (i=0;i<1000;i++)
          {
            if (Spi_send_receive_byte_sd(0xFF) == 0xFF)
              {
                Return 1;
              }
          }
    Return 0;
    }


    Czyli nie wysyłam żadnych komend, nie sprawdzam żadnych rejestrów, tylko podaję impulsy zegarowe i czekam aż na linii danych pojawi się jedynka (a nawet 8 jedynek ;p);

    Uwaga. To pseudo kod ;p

  • #62 14 Paź 2009 00:44
    gotrunks
    Poziom 10  

    Akurat wyłączyłem lapa ;P ale tak rejestr CSD odczytuje raz... przy inizjalizacji karty tam po paru przeszktalceniach obliczeniach otrzymuje 2 liczby.... Nac i Busy a kod wygląda tak:

    Code:

    BYTE write_sector (DWORD address, BYTE bufor[])
    {
     
      BYTE R1 = SD_RESPONSE_ERROR;   // R1_SUCCESS;
     
       
          // wysylam polecenie write block
            if ( R1=send_cmd(SD_WRITE_BLOCK,address<<SdCard.Shift, 0xFF) == R1_SUCCESS)
       {
             
         // 8 cykli opoznienia Nwr
              spi_send_byte(0xff);
         // Token staru danych
         spi_send_byte(SD_START_DATA_BLOCK_TOKEN);
         // wysylam dane z bufora
         for (int i = 0; i < 512; i++)
             spi_send_byte(bufor[i]);   
              // wysylam "CRC"
         spi_send_byte(0xff);
         spi_send_byte(0xff);
       }
          else
       {
         //odpowiwedz nie prawidlowa
         rprintf("CMD18 RESPOSNE_ERROR %d ",R1);
              return R1;
       }
       // pobranie odpowiedz RW 
       R1=spi_send_byte(0xff)& 0x1F; // zamskowane dla odpwowiedzi RW, RRR0xxx1 gdzie RR bity zarezerwowane, x dowolna wartosc
       // sprawdzenie odpowiedzi
       switch(R1)
       { 
           case 0x05: // odpowiedz ok
       
                  for(int i=0;i<=SdCard.Busy;i++) // petla czekajaca
                   spi_send_byte(0xff);
                 // tutaj tez mialem send_cmd(read_sd_status)



                   break;
           case 0x06: // blad zapisu
                   rprintf("zapis er %d adres %d \n",R1,address);
                   break;
           case 0x07: // crc error;
           
       default:
           rprintf("zapis er %d adres %d \n",R1,address);
       }
     
      return R1;
    }


    Po zapisie odrazu karta odpowiada czy zapis się udał po czym trzeba poczekać, ten czas oczekiwania maksymalnie wynosi 250ms... a optymalnie wylicza się go z rejestru CSD... kiedy czas oczekiwania jest za mały to wywala się przeważnie na CMD18 RESPOSNE_ERROR... bądź jest błąd zapisu.

  • #63 14 Paź 2009 00:59
    atom1477
    Poziom 43  

    Ja w ogóle nie odczytuję żadnych rejestrów.
    Tylko dwie komendy do inicjalizacji karty daję, a potem zapis/odczyt sektorów (czyli też po dwie komendy).
    I śmiga.

  • #64 14 Paź 2009 01:04
    gotrunks
    Poziom 10  

    wiem, że tak też można bo tak z początku miałem przy inicjalizacji ale naszła mnie chęć zrobienia tego porządnie...
    Ogólnie to początkowo funkcja wyglądała bliżej twojego pseudokodu, w tej pętli na końcu te 100000 to wartość z sufitu ;) mnie wylicza dla karty SDHC coś koło 60tys przy 25mhz SPI im szybsze SPI tym więcej razy kręci się w pętli. Ponadto u mnie implikacje wprowadza dodatkowe system operacyjny całość działa w systemie operacyjnym freertos wiele wątków opóźnia dodatkowo, ale nawet jak miałem 1 wątek to transfer był daleki od ideału... podobnie bez systemu.

  • #65 14 Paź 2009 01:20
    atom1477
    Poziom 43  

    Spróbój to:

    Code:

    BYTE write_sector (DWORD address, BYTE bufor[])

      BYTE R1 = SD_RESPONSE_ERROR;   // R1_SUCCESS;
     
       
      // wysylam polecenie write block
      if ( R1=send_cmd(SD_WRITE_BLOCK,address<<SdCard.Shift, 0xFF) == R1_SUCCESS)
        {
        // 8 cykli opoznienia Nwr
        spi_send_byte(0xff);
        // Token staru danych
        spi_send_byte(SD_START_DATA_BLOCK_TOKEN);
        // wysylam dane z bufora
        for (int i = 0; i < 512; i++)
          spi_send_byte(bufor[i]);   
       
        // wysylam "CRC"
        spi_send_byte(0xff);
        spi_send_byte(0xff);
        }
      else
        {
        //odpowiwedz nie prawidlowa
        rprintf("CMD18 RESPOSNE_ERROR %d ",R1);
        return R1;
        }
         

      R1=spi_send_byte(0xff)& 0x1F; // zamskowane dla odpwowiedzi RW, RRR0xxx1 gdzie RR bity zarezerwowane, x dowolna wartosc <---- Nie bardzo rozumiem jak to ma działać. Bit 0 zawsze będzie miał wartość "1" więc niemożliwe jest uzyskanie odpowiedzi równej 0x06.
      // sprawdzenie odpowiedzi
      switch(R1)
        { 
        case 0x05: // odpowiedz ok     
            for(int i=0;i<=1000;i++)  //Dobierz dla uzyskania 250ms <-----------------------------
             {
             if (spi_send_byte(0xff) == 0xFF)
               {
               break;
               }
             }
            break;
        case 0x06: // blad zapisu
            rprintf("zapis er %d adres %d \n",R1,address);
            break;
        case 0x07: // crc error;
           
        default:
            rprintf("zapis er %d adres %d \n",R1,address);
        }
     
      return R1;
    }


    O ile się skompiluje, bo nie wiem czy mogą być dwa break-i w jednym segmencie switch-a.

  • #66 14 Paź 2009 10:02
    gotrunks
    Poziom 10  

    mogą być ;-) no i już wiem co było problemem... moje niedopatrzenie bo jak robiłem podobne pętle to zamiast ==0xFF robiłem !=0xFF drobny błąd :E teraz zapis 1 megabajta trwa parę sekund. Dzięki za pomoc ;)

  • #67 14 Paź 2009 10:38
    atom1477
    Poziom 43  

    Spoko. W sumie byłem na 100% pewny że to zadziała ;p
    Ale wyjaśnij mi to:

    Code:

    R1=spi_send_byte(0xff)& 0x1F; // zamskowane dla odpwowiedzi RW, RRR0xxx1 gdzie RR bity zarezerwowane, x dowolna wartosc


    Bo mi sie wydaje że nigdy nie da to odpowiedzi równej 0x06.

  • #68 14 Paź 2009 11:23
    gotrunks
    Poziom 10  

    wyjaśnienie jest proste zamiast 0x06 powinno być 0x0D a zamiast 0x07 powinno być 0x0B być może kiedy to pisałem byłem już nieprzytomny ;)

  • #69 14 Paź 2009 11:30
    atom1477
    Poziom 43  

    Chyba zamiast 0x07 powinno być 0x0F?
    Rozumiem że 0x05 jako jedyne jest dobrze?

  • #70 14 Paź 2009 19:20
    gotrunks
    Poziom 10  

    Tia 0x05 było dobrze, miałem tam używać stałych... co ciekawe stałe były zdefiniowane dobrze, z dokumentacji i na stronie ELMa:

    xxx00101 -> 0x05 dane zapisane ok,
    xxx01011 -> 0x0B błąd crc,
    xxx01101 -> 0x0D błąd zapisu

    Teoretycznie innych błędów nie ma ;) a odpowiedź o zapisie przychodzi niezwłocznie po wysłaniu bloku danych z crc.

  • #71 14 Paź 2009 19:51
    atom1477
    Poziom 43  

    Jest mała zwłoka (kilkaset us).
    Ale wcześniej miałeś problem bo chciałeś od razu ją mieć.
    Układ wysyłał że jeszcze nie zapisał, Ty zapodawałeś opóźnienie 250ms, te kilkaset us później linia danych przyjmowała stan wysoki ale Ty tego nie sprawdzałeś tylko czekałeś pełne 250ms. Rispekt ;p
    Ale rewalacji dalej nie masz? 30KB/s tylko?

  • #72 14 Paź 2009 20:44
    gotrunks
    Poziom 10  

    Zrobię dokładniejsze testy to będę wiedział... póki co wygląda to tak, że puszczam jeden wątek we FreeRTOSie... i czekam aż mi się pojawi napis koniec zapisu, po drodze oprócz zapisu nie robi nic, a czas mierze zegarkiem ;P
    Początkowo czekałem z breakiem kiedy spi_send_byte(0xff)!=0xff a to miało być równe... dlatego później mnie naszło na czekanie pełnych 250ms...

    Może ktoś ma pomysł na jakieś lepsze metody badania prędkości zapisu?

    Dobra transfer jest teraz zadowalający ;) około 500 kB\s przy więcej niż jednym wątku nie jest źle.

  • #73 17 Paź 2009 19:01
    Tytus Kosiarski
    Poziom 14  

    Witam ponownie. Kolejny problem - komunikacja z pamięcią RAM SPI 23K256 w playerku. Od tygodnia próbuję i nic...
    Połączenia RAM-u i karty SD z ARM-em:
    karta SD
    MOSI------------>PA13 (MOSI)
    MISO------------>PA12 (MISO)
    CLK------------->PA14 (SPCK)
    CS-------------->PA11 (NPCS0)

    RAM 23K256
    SI-------------->PA13 (MOSI)
    SO------------->PA12 (MISO)
    SCK------------>PA14 (SPCK)
    CS------------->PA9 (NPCS1)
    HOLD---------->+Vcc

    Definicje

    Code:
    //definicja urządzenia slave SPI
    
    #define SD_Card_Access       0  //wybór karty SD linią PA11 (działa normalnie)
    #define SPI_RAM_Access       1  //wybór pamięci RAM linią PA9(sprawdzone - uaktywnia się wtedy linia NPCS1)


    Kod inicjujący SPI:
    Code:
    void config_SPI(void)  //inicjalizacja SPI
    
    {
     AT91F_PMC_EnablePeriphClock( AT91C_BASE_PMC, 1 << AT91C_ID_SPI ) ;  //enable the clock of the SPI
     AT91F_SPI_Reset(AT91C_BASE_SPI);
     AT91F_SPI_CfgMode( AT91C_BASE_SPI, AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED);//mikrokontroler jest masterem SPI, wybór slave'a poprzez pole bitowe PCS w SPI_MR
     AT91F_SPI_CfgCs( AT91C_BASE_SPI, SD_Card_Access, (0x0 << 24) | (0x0 << 16) | (AT91C_SPI_SCBR - 0xFD00) | AT91C_SPI_BITS_8 | !(AT91C_SPI_CSAAT) | AT91C_SPI_NCPHA | !(AT91C_SPI_CPOL) ); //(dla karty SD) ust. SPI mode 0 (!AT91C_SPI_CPOL) | AT91C_SPI_NCPHA, 8 bitów danych, bez opóźnień między zegarem i danymi, bez opóźnień pomiędzy poszczególnymi danymi, częstotliwość zegara SPCK = MainCLK / (0xFF - 0xFD)
     AT91F_SPI_CfgCs( AT91C_BASE_SPI, SPI_RAM_Access, (0x0 << 24) | (0x0 << 16) | (AT91C_SPI_SCBR - 0xF000) | AT91C_SPI_BITS_8 | !(AT91C_SPI_CSAAT) | AT91C_SPI_NCPHA | !(AT91C_SPI_CPOL) ); //(dla RAM 23K256) ust. SPI mode 0 (!AT91C_SPI_CPOL) | AT91C_SPI_NCPHA, 8 bitów danych, bez opóźnień między zegarem i danymi, bez opóźnień pomiędzy poszczególnymi danymi, częstotliwość zegara SPCK = MainCLK / (0xFF - 0xF0)
     AT91F_SPI_Enable( AT91C_BASE_SPI);  //włączenie SPI
    }


    Kod inicjujący IO:
    Code:
     AT91F_PIO_CfgInput( AT91C_BASE_PIOA, AT91C_PA12_MISO); //konfig PA12 jako wejścia MISO
    
     AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, AT91C_PA13_MOSI); //konfig PA13 jako wyjścia MOSI
     AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, AT91C_PA14_SPCK);  //konfig PA14 jako wyjścia CLK
     AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, AT91C_PA11_NPCS0); //konfig PA11 jako wyjścia (CS0)




     AT91F_PIO_CfgOutput( AT91C_BASE_PIOA, AT91C_PA9_NPCS1); //konfig PA9 jako wyjścia (CS1)
     AT91F_PIO_CfgPeriph( AT91C_BASE_PIOA, AT91C_PIO_PA12 | AT91C_PIO_PA13 | AT91C_PIO_PA14 | AT91C_PIO_PA11, 0x0); //teraz przełączenie linii PA11, PA12, PA13, PA14 na A Peripheral w celu dołączenia sygnału NPCS0 do PA11, MISO do PA12, MOSI do PA13, SPCK do PA14
     AT91F_PIO_CfgPeriph( AT91C_BASE_PIOA, 0x0, AT91C_PIO_PA9); //teraz przełączenie linii PA9 do B Peripheral w celu dołączenia sygnału NPCS1 do PA9


    Kod inicjujący pamięć RAM 23K256
    Code:
      
    
    void init_RAM_SPI()
    {
    unsigned char odb_bajt; //odebrany bajt z RAM
      AT91F_SPI_CfgPCS( AT91C_BASE_SPI, SPI_RAM_Access); //wybór pamięci RAM SPI linią PA9 (NPCS1) 
     while (! (*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)){};//próbowałem z tą pętlą i bez niej
      AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x01, SPI_RAM_Access); //wysłanie do pamięci RAM kodu rozkazu zapisu rejestru statusu pamięci RAM (0x01)
      AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x01, SPI_RAM_Access); //teraz wysłanie do rejestru statusu pamięci RAM danej 0x01 (Byte mode; HOLD pin disabled)
      //while (! (*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)){}; //jak wyżej
      AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x05, SPI_RAM_Access); //teraz wysłanie do pamięci RAM kodu rozkazu odczytu rejestru statusu pamięci RAM (0x05)
       //while (! (*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)){};
      AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SPI_RAM_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK na czas odczytu danej z RAM
      while (! (*AT91C_SPI_SR & AT91C_SPI_RDRF)){}; //próbowałem z tą pętlą i bez niej
       odb_bajt = AT91F_SPI_GetChar( AT91C_BASE_SPI); //spodziewam się wartości odczytanej z rejestru statusu pamięci RAM (w tym przypadku 0x01)
       for(;;); //by zatrzymać dalsze wykonywanie programu.Mam tylko zainicjować RAM
    }


    No właśnie, spodziewałem się wartości w odb_bajt = 0x01 (to, co wysłałem). Dostaję z powrotem w odb_bajt wartość 0x0 lub 0xFF (zależnie od różnych wartości w polu SCBR w SPI_CSR obecności lub nie pętli w funkcji init_RAM). Co robię źle? (pomijając przypadek uszkodzonej pamięci)

    Popatrzyłem w Googlach, mają z tym ludzie generalnie problem. Niestety nie natknąłem się na jakieś rozwiązanie tego problemu. Microchip wypuścił AppNote (AN1287) w którym wspomniał o funkcjach komunikacyjnych z pamięcią umieszczonych w pliku SRAM_Driver.c Komuś się udało trafić w Sieci na ten plik?
    Pozdrawiam, KT_priv

  • #74 20 Paź 2009 14:20
    atom1477
    Poziom 43  

    A jeszcze jedno.
    Za co konkretnie MicroSoft każe sobie płacić?
    Rozumiem że za tworzenie plików z długimi nazwami.
    Ale jak pliki z długimi nazwami na karcie już są to co?
    Nie mogę ich odczytać?
    Owszem mogę użyć krótkiego aliasu, ale on z oczywistych względów ma inną zawartość niż cała nazwa pliku.
    Wic musiał bym jedynie rozkodować długą nazwę (nic bym nie tworzył) i jak by się okazało że to ten plik to go otworzyć (idąc już po krótkim aliasie).
    Problem jest, bo mimo że plik ma krótką nazwę to Windows zapisuje mi go używając formatowania dla długich nazw (Prawdopodobnie żeby zmusić producentów sprzętu do płacenia licencji).
    Mam plik „POMIARY1.CSV”.
    Krótki alias to „POM~1.CSV” (czy jakoś tak) i po tym aliasie otwierać nie mogę, bo możgą być jeszcze pliki „POMIARY2.CSV” albo np. „POMIAR34.CSV” a te pliki muszę odróżnić.
    Więc jak to jest?

    Tytus Kosiarski: Może po zapisie a przed odczytem ustaw linię CS w stan wysoki na chwilę.

  • #75 20 Paź 2009 17:03
    radioda
    Poziom 15  

    Jeśli jest kilka plików, które maja taki sam początek w nazwie to system plików powinien je ponumerować innymi liczbami po tyldzie (POM~1.CSV, POM~2.CSV itp.) Ponadto krótki alias jest typu 8+1+3, czyli osiem znaków na nazwe + jeden znak na kropkę + trzy znaki na rozszerzenie, więc plik POMIARY1.CSV będzie dostępny pod taką właśnie nazwą bez konieczności skracania.

  • #76 20 Paź 2009 17:24
    atom1477
    Poziom 43  

    1. No i właśnie to jest problem. Bo system mi to ponumeruje więc skąd układ ma wiedzieć który plik to który? Układ ma działać sam, bez ingerencji człowieka.
    Jeżeli utworzę pliki w takiej kolejności:
    POMIARY1
    POMIARY2
    POMIARY3

    to powstaną aliasy:
    POM~1
    POM~2
    POM~3

    i teoretycznie układ mógł by odczytywać plik POM~1 chcąc się dobrać do POMIARY1.

    ale jak utworzę w takiej kolejności:
    POMIARY2
    POMIARY3
    POMIARY1

    to też utworzy mi aliasy:
    POM~1
    POM~2
    POM~3
    Tyle że teraz POM~1 będzie wskazywał na POMIARY2.
    Nie mogę sobie pozwilic na taki odczyt.
    Niestety system plików numeruje w pliku zgodnie z kolejnością tworzenia, z nie zgodnie z nazwą.

    2. Nie będzie tak dostępny. Sprawdziłem. Choćby nazwa miała 1 znak to dostęp będzie przez nazwę długą.

  • #77 20 Paź 2009 17:34
    radioda
    Poziom 15  

    Wszystko zależy od inteligencji oprogramowania. Można je przecież napisać tak żeby korzystało z krótkich aliasów i zaraz po utworzeniu pliku przechwycić jego krótki alias i za jego pomocą odnosić się do pliku. Ponadto można wyciągnąć z pliku jego długą nazwę sprawdzając czy jest to napewno ten plik o który nam chodzi. Może nie tak z pliku jak z tablicy FAT, choć nie wiem gdzie ona się dokładnie znajduje.

  • #78 20 Paź 2009 19:34
    atom1477
    Poziom 43  

    No ale jak przechwycić? Utwarzanie pliku będzie na kompie, a odczyt dopiero w urządzeniu.
    Wyciąganie długiej nazwy to oczywiste rozwiązanie i je juz mam.
    Chodzi mi o to czy to jest legalne jeżeli nie wykupię licencji.

  • #79 20 Paź 2009 19:46
    radioda
    Poziom 15  

    Wydaje mi sie, że to program na uC robi konwersję z nazwy długiej na krótką dla swoich potrzeb, żeby było prościej odwoływać się do plików, a skoro tak, to można to miejsce w programie znaleźć i zwrócić ten krótki alias po wywołaniu funkcji tworzącej plik. Co do legalności niestety nie potrafie Ci pomóc.

  • #80 20 Paź 2009 20:24
    atom1477
    Poziom 43  

    Nie rozumiesz. Program pisałem sam :D
    Dobrze wiem gdzie nazwa jest długa a gdzie krótka. Chodziło mi tylko czy mogę tego używać. Ale skoro nie wiesz no to trudno.

  • #81 20 Paź 2009 20:55
    radioda
    Poziom 15  

    Skoro pisałeś sam to kto Ci zabroni używać własnego programu? Pozatym pisałeś to na podstawie jakiejś dokumentacji VFAT, której raczej nie ukradłeś, tylko była ogólnie dostępna, a skoro tak to nie przejmował bym sie licencjami. Dla świętego spokoju napisz do Billa i zapytaj ;)

  • #82 20 Paź 2009 21:16
    atom1477
    Poziom 43  

    No nie bardzo. Patenty też są w internecie za free a nie można ich wykorzystywać.
    Jak by mi się z Billem chciało gadać to bym tutaj głowy nie zawracał ;p

  • #83 25 Paź 2009 02:40
    Tytus Kosiarski
    Poziom 14  

    Witam ponownie. Udało mi się pogadać już z pamięcią RAM 23K256 :)
    Dla zainteresowanych kod poniżej (zegar MCK = 45,1584MHz):

    Code:
    void config_SPI(void)  //inicjalizacja SPI
    
    {
     AT91F_SPI_Reset(AT91C_BASE_SPI);
     AT91F_SPI_CfgMode( AT91C_BASE_SPI, AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED);  //mikrokontroler jest masterem SPI, wybór slave'a SPI poprzez pole bitowe PCS w SPI_MR
     AT91F_SPI_CfgCs( AT91C_BASE_SPI, SD_Card_Access, (0x0 << 24) | (0x0 << 16) | (AT91C_SPI_SCBR - 0xFD00) | AT91C_SPI_BITS_8 | !(AT91C_SPI_CSAAT) | AT91C_SPI_NCPHA | !(AT91C_SPI_CPOL) ); //ust. SPI mode 0 (!AT91C_SPI_CPOL) | AT91C_SPI_NCPHA, 8 bitów danych, bez opóźnień między zegarem i Chip Select, bez opóźnień pomiędzy poszczególnymi danymi(potrzebne dla kart SD), częstotliwość zegara = MainCLK / (0xFF - 0xFD)
     AT91F_SPI_Enable( AT91C_BASE_SPI);  //włączenie SPI
    }


    Operacje na RAM:
    Code:
    void init_RAM_SPI(void)
    
    {
      unsigned char odb_bajt;
      AT91F_SPI_CfgCs( AT91C_BASE_SPI, SPI_RAM_Access, (0x0 << 24) | (0x28 << 16) | (AT91C_SPI_SCBR - 0xF900) | AT91C_SPI_BITS_8 | !(AT91C_SPI_CSAAT) | AT91C_SPI_NCPHA | !(AT91C_SPI_CPOL) ); //ust. SPI mode 0 (!AT91C_SPI_CPOL) | AT91C_SPI_NCPHA, 8 bitów danych, z opóźnieniem między zegarem i Chip Select, bez opóźnień pomiędzy poszczególnymi danymi, częstotliwość zegara = MainCLK / (0xFF - 0xF9)
      AT91F_SPI_CfgPCS( AT91C_BASE_SPI, SPI_RAM_Access); //wybór pamięci RAM SPI linią PA9 (NPCS1) 
      AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x01, SPI_RAM_Access); //wysłanie do pamięci RAM rozkazu zapisu rejestru statusu pamięci RAM (0x01)
      AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x01, SPI_RAM_Access); //teraz wysłanie do rejestru statusu pamięci RAM danej 0x01 (Byte mode; HOLD pin disabled)
      AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x05, SPI_RAM_Access); //wysłanie do pamięci RAM rozkazu odczytu rejestru statusu pamięci RAM (0x05)
      AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SPI_RAM_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK
      odb_bajt = AT91F_SPI_GetChar( AT91C_BASE_SPI);
    }


    void write_data_to_RAM(void)
    {
     unsigned short adres = 0x0;
     unsigned char dana = 0x0;
     AT91F_SPI_CfgCs( AT91C_BASE_SPI, SPI_RAM_Access, (0x0 << 24) | (0x0 << 16) | (0x0C << 8) | AT91C_SPI_BITS_8 | !(AT91C_SPI_CSAAT) | AT91C_SPI_NCPHA | !(AT91C_SPI_CPOL) ); //ust. SPI mode 0 (!AT91C_SPI_CPOL) | AT91C_SPI_NCPHA, 8 bitów danych, bez opóźnień między zegarem i Chip Select, bez opóźnień pomiędzy poszczególnymi danymi, częstotliwość zegara = MainCLK / 0x0C
     AT91F_SPI_CfgPCS( AT91C_BASE_SPI, SPI_RAM_Access); //wybór pamięci RAM SPI linią PA9 (NPCS1) 
     for (adres = 0; adres < 512; adres++) //w tej pętli na próbę wypełnienie początkowych 512 bajtów RAM kolejnymi wartościami zmiennej dana
     {
       AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x02, SPI_RAM_Access); //wysłanie do pamięci RAM rozkazu zapisu komórki pamięci
       AT91F_SPI_PutChar(AT91C_BASE_SPI, ((adres & 0xFF00) >> 8), SPI_RAM_Access); //wysłanie do pamięci RAM MSByte adresu
       AT91F_SPI_PutChar(AT91C_BASE_SPI, (adres & 0xFF), SPI_RAM_Access); //wysłanie do pamięci RAM LSByte adresu
       AT91F_SPI_PutChar(AT91C_BASE_SPI, dana, SPI_RAM_Access); //wysłanie do pamięci RAM danej
       dana++;
     }
    }


     
    void read_data_from_RAM(void)
    {
     unsigned short adres;
     unsigned char odb_bajt;
     AT91F_SPI_CfgCs( AT91C_BASE_SPI, SPI_RAM_Access, (0x0 << 24) | (0x0 << 16) | (0x0C << 8) | AT91C_SPI_BITS_8 | !(AT91C_SPI_CSAAT) | AT91C_SPI_NCPHA | !(AT91C_SPI_CPOL) ); //ust. SPI mode 0 (!AT91C_SPI_CPOL) | AT91C_SPI_NCPHA, 8 bitów danych, bez opóźnień między zegarem i Chip Select, bez opóźnień pomiędzy poszczególnymi danymi, częstotliwość zegara = MainCLK / 0x0C
     AT91F_SPI_CfgPCS( AT91C_BASE_SPI, SPI_RAM_Access); //wybór pamięci RAM SPI linią PA9 (NPCS1) 
     for (adres = 0; adres < 512; adres++)  //w tej pętli wypełnienie tablicy_bajtow_danych zawartością odczytaną z RAM
     {
       AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x03, SPI_RAM_Access); //wysłanie do pamięci RAM rozkazu odczytu komórki pamięci
       AT91F_SPI_PutChar(AT91C_BASE_SPI, ((adres & 0xFF00) >> 8), SPI_RAM_Access); //wysłanie do pamięci RAM MSByte adresu
       AT91F_SPI_PutChar(AT91C_BASE_SPI, (adres & 0xFF), SPI_RAM_Access); //wysłanie do pamięci RAM LSByte adresu
       AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SPI_RAM_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK
       AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SPI_RAM_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK
       odb_bajt = AT91F_SPI_GetChar( AT91C_BASE_SPI);
       tablica_bajtow_danych[adres] = odb_bajt;
     }
    }


    Niestety, w tych przykładach częstotliwość taktowania RAM jest poniżej fmax podawanej przez producenta pamięci. Ale w projekcie playerka akurat nie potrzebuję szybkiego dostępu do tej pamięci :)
    Pozdrawiam, KT_priv

  • #84 01 Lis 2009 23:35
    Tytus Kosiarski
    Poziom 14  

    Witam ponownie
    Przerzuciłem już w programie playerka drzewo plików i podkatalogów odczytane z karty SD do RAM 23K256. Tym sposobem zwolniłem RAM mikrokontrolera. Obecnie mam 27kB wolnego RAM-u w mikrokontrolerze :) Przyda się, gdy będę próbować dekodować i odtwarzać inne formaty audio (nadal interesuje mnie dekodowanie WMA - może ktoś coś próbował robić z tym?).
    Jeszcze kilka spostrzeżeń, które stały się moim udziałem podczas uruchamiania komunikacji z RAM 23K256:
    1. Ustawienia rejestrów SPI do komunikacji z RAM (które podałem w poście z 25.10) są odpowiednie dla podanego zegara i _1WS_ .Playerek mi chodzi na 0WS, toteż przed wymianą danych z RAM ustawiam 1WS, po zakończeniu wymiany danych ustawiam z powrotem 0WS. Nie odbija się to na jakości dźwięku, bo dostęp do tej RAM odbywa się tylko przy kopiowaniu drzewa plików i podkatalogów z karty SD do tej RAM i przed rozpoczęciem odtwarzania, gdy z tej RAM pobieram dane pliku, który chcę odtwarzać. Podczas odtwarzania wybranego pliku nie ma już odwołań do tej RAM.
    2. Zauważyłem, że musi być ciągły przepływ danych między RAM i mikrokontrolerem podczas dostępu do RAM. Oznacza to, że wszystkie dane muszą już być gotowe przed zapisaniem ich do RAM lub z RAM muszę odczytać naraz jakąś porcję danych. Zrobiłem to najprościej w programie playerka definiując tymczasową tablicę o pojemności wystarczającej do pomieszczenia potrzebnych danych do zapisu do RAM. Najpierw wypełniam tą tablicę, gdy już jest ona gotowa, to w pętli:

    Code:
     
    
    unsigned int backup = AT91F_MC_EFC_GetModeReg(AT91C_BASE_MC); //zapamiętanie oryginalnego ustawienia WS
    AT91F_MC_EFC_CfgModeReg( AT91C_BASE_MC, (AT91C_MC_FMCN | AT91C_MC_FWS_1FWS)); //ustawienie 1WS
     AT91F_SPI_CfgCs( AT91C_BASE_SPI, SPI_RAM_Access, (0x0 << 24) | (0x0 << 16) | (0x0C << 8) | AT91C_SPI_BITS_8 | !(AT91C_SPI_CSAAT) | AT91C_SPI_NCPHA | !(AT91C_SPI_CPOL) ); //ust. SPI mode 0 (!AT91C_SPI_CPOL) | AT91C_SPI_NCPHA, 8 bitów danych, bez opóźnień między zegarem i Chip Select, bez opóźnień pomiędzy poszczególnymi danymi, częstotliwość zegara = MainCLK / 0x0C
     AT91F_SPI_CfgPCS( AT91C_BASE_SPI, SPI_RAM_Access); //wybór pamięci RAM SPI linią PA9 (NPCS1) 
     for (address = 0; address < sizeof(temp_array); address++) //w tej pętli przepisanie wartości z tymczasowej tablicy wpisów do RAM
     {
       data_to_write = temp_array[address];
       AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x02, SPI_RAM_Access); //wysłanie do pamięci RAM rozkazu zapisu komórki pamięci
       AT91F_SPI_PutChar(AT91C_BASE_SPI, ((address & 0xFF00) >> 8), SPI_RAM_Access); //wysłanie do pamięci RAM MSByte adresu
       AT91F_SPI_PutChar(AT91C_BASE_SPI, (address & 0xFF), SPI_RAM_Access); //wysłanie do pamięci RAM LSByte adresu
       AT91F_SPI_PutChar(AT91C_BASE_SPI, data_to_write, SPI_RAM_Access); //wysłanie do pamięci RAM danej
     }
     AT91F_MC_EFC_CfgModeReg( AT91C_BASE_MC, backup);//odtworzenie oryginalnej nastawy WS

    przepisuję zawartość temp_array do RAM. Kod ten uwzględnia również zmianę WS.
    Natomiast odczyt z RAM mam zrobiony tak:
    Code:
    unsigned int backup = AT91F_MC_EFC_GetModeReg(AT91C_BASE_MC); //zapamiętanie oryginalnego ustawienia WS
    
    AT91F_MC_EFC_CfgModeReg( AT91C_BASE_MC, (AT91C_MC_FMCN | AT91C_MC_FWS_1FWS)); //ustawienie 1WS
     AT91F_SPI_CfgCs( AT91C_BASE_SPI, SPI_RAM_Access, (0x0 << 24) | (0x0 << 16) | (0x0C << 8) | AT91C_SPI_BITS_8 | !(AT91C_SPI_CSAAT) | AT91C_SPI_NCPHA | !(AT91C_SPI_CPOL) ); //ust. SPI mode 0 (!AT91C_SPI_CPOL) | AT91C_SPI_NCPHA, 8 bitów danych, bez opóźnień między zegarem i Chip Select, bez opóźnień pomiędzy poszczególnymi danymi, częstotliwość zegara = MainCLK / 0x0C
     AT91F_SPI_CfgPCS( AT91C_BASE_SPI, SPI_RAM_Access); //wybór pamięci RAM SPI linią PA9 (NPCS1) 
     for (address = 0; address < sizeof(temp_array); address++)  //w tej pętli wypełnienie tablicy_bajtow_danych zawartością odczytaną z RAM
     {
       AT91F_SPI_PutChar(AT91C_BASE_SPI, 0x03, SPI_RAM_Access); //wysłanie do pamięci RAM rozkazu odczytu komórki pamięci
       AT91F_SPI_PutChar(AT91C_BASE_SPI, ((address & 0xFF00) >> 8), SPI_RAM_Access); //wysłanie do pamięci RAM MSByte adresu
       AT91F_SPI_PutChar(AT91C_BASE_SPI, (address & 0xFF), SPI_RAM_Access); //wysłanie do pamięci RAM LSByte adresu
       AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SPI_RAM_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK
       AT91F_SPI_PutChar(AT91C_BASE_SPI, 0xFF, SPI_RAM_Access); //wystawianie 0xFF na MOSI, by utrzymać aktywność CLK
       data_to_read = AT91F_SPI_GetChar( AT91C_BASE_SPI);
       temp_array[address] = data_to_read;
     }
     AT91F_MC_EFC_CfgModeReg( AT91C_BASE_MC, backup);//odtworzenie oryginalnej nastawy WS

    i dalej mogę zająć się obróbką danych umieszczonych w temp_array. To jest przykład, gdy naraz jest zapisywana lub odczytywana cała pamięć RAM. Gdy trzeba zapisywać lub odczytywać tylko porcje danych, to odpowiednio trzeba obliczać jeszcze adresy tak, by poprawnie adresować kawałkami RAM i nie wyskoczyć tym adresem poza rozmiar temp_array.
    Pozdrawiam, KT_priv

  • #85 05 Lis 2009 20:53
    Tomasso
    Poziom 16  

    Witam, czy ten układ może odtwarzać pliki typu wav ?

  • #86 05 Lis 2009 21:04
    atom1477
    Poziom 43  

    Mógł. Ale czy teraz może to nie wiem.
    Ale skoro mógł to dodanie tej możliwości spowrotem będzie więcej niż łatwe.

  • #87 05 Lis 2009 21:15
    Tomasso
    Poziom 16  

    Chce zrobić podobny układ do czytania wav na płytce EVBmmTm z Propox

  • #88 05 Lis 2009 21:20
    atom1477
    Poziom 43  

    Z wav-em nie będziesz miał większych problemów. Nie licząc ogromnego wymaganego transferu od karty do procesora.

  • #89 05 Lis 2009 21:30
    Tomasso
    Poziom 16  

    Na karcie będzie nagrane np 30 próbek i po naciśnięciu odpowiedniego przycisku ma odtwarzać dany dźwięk w pętli, procesor który chce użyć to AT91SAM7S.

  • #90 06 Lis 2009 07:12
    Tytus Kosiarski
    Poziom 14  

    Witam
    Zrezygnowałem z możliwości odtwarzania wav-ów w tym projekcie - pliki wav z muzą zajmowałyby zbyt dużo miejsca na karcie SD. Ale dorobienie tej możliwości jest łatwe - po prostu trzeba odczytane dane z pliku wav podawać od razu do przetwornika D/A. Można też zastosować technikę podwójnego buforowania - jeden wypełniony bufor jest wysyłany przez DMA do D/A, gdy w tym czasie drugi bufor jest wypełniany nową porcją danych z odtwarzanego wav-a.
    Pozdrawiam, KT_priv