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

[Bascom/assembler][AVR] - lookup na asm

mirekk36 08 Lip 2008 09:05 3373 13
  • #1 5322501
    mirekk36
    Poziom 42  
    Witam,

    próbuję od wczoraj przerobić wprost w Bascomie, dokładnie w przerwaniu pewne polecenie na asembler:

    PORTA = Lookup(cyfry(nr_wysw) , Tabela)


    gdzie:

    cyfry to --> Dim Cyfry(4) as Byte
    nr_wysw --> Dim nr_wysw as Byte
    Tabela - to tabela zdefiniowanych cyfr dla wyświetlacza LED

    mam zrobione wyświetlanie multipleksowane i wszystko działa wyśmienicie. Teraz zacząłem całe przerwanie pisać w asm aby skorzystać z opcji NOSAVE i "ręcznie" odłożyć potrzebne rejestry na stos. Wszystko w przerwaniu jak inkrementacja nr_wysw, czy Select Case dla gaszenia i zapalania poszczególnych wyświetlaczy ładnie już mi śmiga w asemblerze dzięki czemu kodu zrobiło się duuużo mniej a i dzięki temu samo przerwanie szybciej się wykonuje

    jednak dręczy mnie jeszcze ten Lookup, próbowałem tak:

       $asm
          ' ładuję do pary rejestrów Z adres pierwszej komórki pamięci w której jest umieszczona 1sza cyfra
          Loadadr Cyfry(1) , Z   
         ' ładuję do R16 wartość zmiennej nr_wysw czyli aktualnie świecący wyświetlacz
          lds r16, {Nr_wysw}
         ' pomniejszam go o 1 bo tablice są indeksowane od 1 i nr_wysw przyjmuje wartości od 1 do 4
          dec r16
         ' dodaję do zl wartość bieżącego znaku na wyświetlaczu
          add zl, r16
          lpm
          mov r16, r0
    
          'ldi r16, 3 - gdy ta linijka nie jest zaremowana to dalsza część kodu ładnie działa i wyświetla same 3-ki
    
          ldi zl, LOW(Tabela * 2)
          ldi zh, high(Tabela * 2)
          add zl, r16
          lpm
          Out Porta , R0
       $end Asm


    ale chyba coś może źle mi się dodaje w tym poleceniu add zl, r16 ??? chyba powinienem użyć czegoś jak ADIW ale tym można dodać stałą tylko.

    próbowałem więc jeszcze tak jeśli chodzi o ten mój fragment źle działającego kodu:

          Loadadr Cyfry(1) , Z
          lds r16, {Nr_wysw}
          dec r16
          add zl, r16
          Brcc Pp2
          inc zh
       Pp2:
          lpm
          mov r16, r0


    czyli po dodaniu do zl jeśli nie było przeniesienia to nic się nie dzieje a jesli było to zwiększana jest zawartość zh o 1 (dobrze kombinuję?)

    a może w ogóle źle jest przekazywany adres w :

    Loadadr Cyfry(1) , Z


    jeśli chodzi o tablicę ???

    może ktoś naprowadzi mnie na jakiś trop???

    pozdrawiam i z góry dziękuję
  • Pomocny post
    #2 5322838
    BoskiDialer
    Poziom 34  
    dodawanie do ZH:ZL można zrobić w dość prosty sposób:
    add ZL, r16
    adc ZH, jakis_rejestr_o_wartosci_0

    Jeśli tablica "cyfry" jest "Dim Cyfry(4) as Byte", to bardziej prawdopodobne jest, że znajduje się w pamięci RAM a nie programu, stąd szacunkowo kod powinien wyglądać jakoś tak (jakoś, ponieważ nie znam bascoma):
       $asm 
          ' laduje do pary rejestrów Z adres pierwszej komórki pamieci w której jest umieszczona 1sza cyfra 
          Loadadr Cyfry(1) , Z    
         ' laduje do R16 wartosc zmiennej nr_wysw czyli aktualnie swiecacy wyswietlacz 
          lds r16, {Nr_wysw} 
         ' pomniejszam go o 1 bo tablice sa indeksowane od 1 i nr_wysw przyjmuje wartosci od 1 do 4 
          dec r16 
         ' dodaje do zl wartosc biezacego znaku na wyswietlaczu 
          add zl, r16
          ldi r16, 0
          adc zh, r16
          ld r16, Z
    
          ldi zl, LOW(Tabela * 2) 
          ldi zh, high(Tabela * 2) 
          add zl, r16 
          ldi r16, 0
          adc zh
          lpm
          Out Porta , R0 
       $end Asm
  • #3 5322844
    don diego
    Poziom 32  
    Witam
    Na wyświetlanie cyfr napisałem kiedyś taką procedurkę:
    wyswietl: ;wyświetla wartość z rejestru temp
    ldi ZH, high(cyfry<<1);ładuj rejestr Z adresem, pod którym umieszczono
    ldi ZL, low(cyfry<<1) ;początek tablicy cyfr
    clr R17
    add ZL, temp ;dodaj zawartość rejestru temp (cyfra do wyswietlenia) do wskaźnika Z
    add ZH, R17 ;R17=0
    lpm temp, Z
    out PORTB,temp
    ret
  • Pomocny post
    #4 5322845
    BoskiDialer
    Poziom 34  
    Pomiędzy ld a lpm można jeszcze kod zoptymalizować:
          ld ZL, Z
    	  clr ZH
    	  ' dodanie adresu do Z
    	  subi ZL, low(-( Tabela * 2 )) 
    	  sbci ZH, high(-( Tabela * 2 )) 
          lpm


    Dodano po 1 [minuty]:

    don diego: twój kod może nie działać, ponieważ ZH się nie zmienia - dodajesz do niego samo zero (add) zamiast zero+przeniesienie (adc)
  • #5 5322856
    don diego
    Poziom 32  
    Przy małych tablicach (cyfry plus kilka znaków) działa bezbłędnie. ZH jest chyba potrzebne dopiero gdy chcemy wskazać jakiś odległy element tablicy (powyżej 255?).
  • Pomocny post
    #6 5322858
    BoskiDialer
    Poziom 34  
    Nie. Dodawanie do ZH jest potrzebne, gdy górny bajt adresu jest inny w pierwszej a inny w ostatniej komórce tabeli.. jeśli tablica ma 2 elementy o adresach 0x8FF oraz 0x900, to bez tego dodawania uzyskasz adresy 0x8FF i 0x800 (brak dodania przeniesienia).
  • #7 5322879
    don diego
    Poziom 32  
    Aha, teraz rozumiem o co biega:)
    Czy w czystym asemblerze też może wystąpić takie umieszczenie tablicy? Wydaje mi się, że tam zawsze jest umieszczana od początku komórki pamięci, prawda? Moje rozwiązanie jest z programu czysto assemblerowego.
  • Pomocny post
    #8 5322893
    BoskiDialer
    Poziom 34  
    Jeśli ręcznie rozmieszczasz zmienne w pamięci, to możesz tablice (mające do 256 bajtów) porozmieszczać tak, aby wszystkie komórki w jej obrębie mały górną część adresu taką samą, przez co w kodzie możesz pominąć dodawanie do ZH. Niestety jeśli zmienne rozmieszcza kompilator, który traktuje całą pamięć jako przestrzeń liniową i nie czyni żadnych dodatkowych działań z rozmieszczaniem komórek w pamięci, to operowanie na ZH jest niezbędne.
  • #9 5323225
    mirekk36
    Poziom 42  
    BoskiDialer -> hmm zrobiłem dodawanie tak jak pisałeś:

       $asm
          Loadadr Cyfry(1) , Z
          lds r16, {Nr_wysw}
          dec r16
    
          add zl, r16
          ldi r16,0
          adc zh, r16
    
          lpm
          mov r16, r0
    
          'ldi r16, 3
    
          ldi zl, LOW(Tabela * 2)
          ldi zh, high(Tabela * 2)
          add zl, r16
          lpm
          Out Porta , R0
       $end Asm


    z tym adc (masz rację) tylko nadal adresy w ZH:ZL wskazują mi na jakieś inne miejsce w pamięci ram niż chcę bo nadal wyświetla zawartości jakieś przypadkowe.

    Może w jakiś dziwny sposób działa to loadadr Cyfra(1), Z ???

    i oczywiście bardziej chodzi mi tu o poradę w/s powiązania Bascoma z assemblerem (przekazywanie parametrów) bo w czystym asemblerze nie mam problemu z takim wyświetlaniem. Ale tu mi coś "śmierdzi" to przekazywanie parametru do Cyfry(1)
  • #11 5323292
    mirekk36
    Poziom 42  
    Balu -> w tej drugiej części kodu, który pokazałem powyżej:

          ldi zl, LOW(Tabela * 2) 
          ldi zh, high(Tabela * 2) 
          add zl, r16 
          lpm 
          Out Porta , R0 


    czytam oczywiście z flasha , ale w jego pierwszej części:

          Loadadr Cyfry(1) , Z 
          lds r16, {Nr_wysw} 
          dec r16 
    
          add zl, r16 
          ldi r16,0 
          adc zh, r16 
    
          lpm 
          mov r16, r0 


    czytam (tzn taką mam nadzieję) z pamięci RAM bo zmienna tablicowa Cyfry(4) jest nie gdzie indziej tylko w pamięci RAM. tylko jak mówię, może to nie jest dobry sposób na przekazanie jej do pary rejestrów ZH:ZL żeby odczytać za pomocą LPM

    oczywiście loadadr to polecenie Bascomowe służące do przekazania ADRESU zmiennej do par rejestrów takich jak X lub Z właśnie. Ale jak mówię może albo na pewno gdzieś robię babola chyba
  • Pomocny post
    #12 5323307
    BoskiDialer
    Poziom 34  
    pamięć ram i pamięć programu nie znajdują się w tej samej przestrzeni. LPM (load program memory) odczytuje z pamięci programu, LD (load data) wczytuje z przestrzeni pamięci. Zmień LPM na LD r16, Z (pomijając mov r16, r0) tak jak napisałem w drugim poście tematu.
  • Pomocny post
    #13 5323320
    Balu
    Poziom 38  
    mirekk36 napisał:
    Balu -> w tej drugiej części kodu, który pokazałem powyżej:

          Loadadr Cyfry(1) , Z 
          lds r16, {Nr_wysw} 
          dec r16 
    
          add zl, r16 
          ldi r16,0 
          adc zh, r16 
    
          lpm 
          mov r16, r0 


    czytam (tzn taką mam nadzieję) z pamięci RAM


    No właśnie z flasha ;-) LoadPROGRAMMemory

    Dodano po 38 [sekundy]:

    No i mnie kolega boski wyprzedził:P
  • #14 5323347
    mirekk36
    Poziom 42  
    Balu -> no tak zgodnie z tym co podpowiedział dalej BoskiDialer to miałeś rację, próbuję odczytać z flasha - ten nieszczęsny LPM (eeeh no chwila nieuwagi)

    BoskiDialer -> WIELKIE DZIĘKI !!!! - kurczę w tym drugim poście nie dostrzegłem niestety tych twoich poprawek w kodzie i to był mój największy błąd. Czyli dokładnie tak jak sugerowałeś w pierwszym przypadku musiałem zamienić LPM na LD , a poza tym koniecznie ale to koniecznie pododawać

    ldi r16,0
    adc zh, r16


    teraz wszystko działa baaardzo dobrze - dzięki i pozdrawiam wszystkich :)

    Dodano po 4 [minuty]:

    ok temat uważam za zamknięty, teraz już cały kod przerwania mogę sobie skrócić, maksymalnie przyśpieszyć pisząc wstawkę asemblerową do Bascoma ;) fajnie to wszystko współdziała
REKLAMA