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

[Atmega88][asm] - Karta MMC po SPI - nie incjuje się

grysek 29 Lis 2009 15:09 2561 21
  • #1 7323326
    grysek
    Poziom 19  
    Witam,

    korzystając z materiałów z Elektroniki Praktycznej napisałem program do obsługi karty, narazie samą inicjalizację (zamieszczam same podprogramy bo cały kod jest bardzo długi).
    ;--------------------* SPI *----------------------
    spi_init:
    ldi 		acc, (1<<MOSI) | (0<<MISO) | (1<<SCK) | (1<<CS)
    out 		DDRB, acc
    ldi 		acc, (1<<SPE) | (1<<MSTR) 
    out 		SPCR, acc
    ret
    
    spi_send:
    out			SPDR, data
    spi_1:
    in			acc, SPSR
    sbrs  		acc,SPIF
    rjmp		spi_1
    in			data, SPDR
    ret
    
    ;--------------------* MMC *----------------------
    
    mmc_init:
    sbi		PORTB, CS		;stan wysoki CS
    ldi		petla, 10		;wyslij 80 cykli zegarowych
    init_loop:
      dec		petla		;10 * 8 = 80
      breq		CMD0
      ldi		data, 0xFF
      rcall		spi_send	; <---
    rjmp	init_loop
    
    sbi		PORTC, LED
    
    CMD0:					;Przełącz karte w tryb SPI
    ldi		komenda, 0
    rcall	mmc_cmd
    
    CMD1:					;Wyjdz ze stanu IDLE
    ldi		komenda, 1		
    rcall	mmc_cmd
    sbrc	data, IDLE
    rjmp	CMD1
    	
    ldi		datau, 'O'
    rcall	uart_send
    ldi		datau, 'K'
    rcall	uart_send
    ret
    
    mmc_cmd:
    cbi		PORTB, CS
    ori		komenda, 0x40
    mov 	data, komenda
    rcall	spi_send
    lds		data, addr1
    rcall	spi_send
    lds		data, addr2
    rcall	spi_send
    lds		data, addr3
    rcall	spi_send
    lds		data, addr4
    rcall	spi_send
    ldi		data, 0x95 
    rcall	spi_send
    
    ldi		petla, 10
    cmd_loop:
     dec		petla
     breq		cmd_end
     ldi		data,0xFF
     rcall		spi_send
     sbrc		data, BUSY
    rjmp 	cmd_loop
    cmd_end:	
    ret
    


    Program zatrzymuje se na wieki w miejscu oznaczonym strzałką w komentarzu. Zupełnie tak jakby karta nie odpowiadała. Wiem to po tym że dioda podpięta Do PORTC, LED nie zapala się. Połączenia sprawdzałem kilka razy i wszystko jest ok.

    Do uzyskania odpowiedniego zasilania dla karty używam LM317 i napięcie zasilania udało mi się uzyskać 3,2V czyli powinno wystarczyć chyba nie?
    Proszę o pomoc bo siedzę już nad tym kilka dni i nie mogę nic wymyślić ;/

    Pozdrawiam
  • #2 7323546
    asembler
    Poziom 32  
    SPISEND OUT SPDR,R16
    SPIFRA JBI SPSR,SPIF ;zbadaj czy bit w rejestrze SPSR jest usrtawiony
    JR SPIFRA
    CBI SPSR,SPIF
    IN R16,SPDR
    RET
    U mnie to dziala z tym ze ja badam bezposrednio bit z rejestru specjalnego a nie przepisuje do rejestru ogolnego, moze w tym tkwi problem?
  • #3 7325550
    grysek
    Poziom 19  
    Chyba raczej to nie to, ponieważ w sumie to na jedno wychodzi a pozatym nie da się bitów rejestru SPSR sprawdzać bezpośrednio (instrukcje sbic,sbis) ponieważ adres tego rejestru jest za duży i wykracza poza zakres tej instrukcji. Może ma ktoś jeszcze jakieś pomysły? Każda wskazówka jest cenna.

    P.S to co napisałeś to napewno są instrukcje asemblera AVR?

    Pozdrawiam
  • #4 7325659
    asembler
    Poziom 32  
    Nie dowidzialem ze to atmega88. A jezeli ten rejset jest spoza dzialania instrukcji OUT,IN to trzeba go inaczej odczytywac (o ile sie nie myle) trzeba je czytac za pomocą istrukcji odczytu pamieci RAM


    PS moj kompilator nie buntuje sie na takie mnemoniki a pisanie przebiega wiele szybciej
  • #5 7325915
    grysek
    Poziom 19  
    Rejestr SPSR ma adres 0x2D czyli może byc odczytywany/zapisywany przez in/out których zakres jest do 0x3F, natomiast nie może byc sprawdzany przez sbic/sbis bo ich zakres jest do 0x1F.
    Napewno nie tu jest błąd.

    Ma ktoś jeszcze jakieś propzycje? Proszę o podpowiedzi. Może ktoś robił coś podobnego? Aha i zapomniałem dodać że przy budowie korzystałem ze schematu: http://www.captain.at/electronic-atmega16-mmc-schematic.png

    Pozdrawiam
  • #6 7325940
    asembler
    Poziom 32  
    Zobacz czy dobrze zadeklarowales typ procesora
    zmien procesor
  • #7 7325984
    grysek
    Poziom 19  
    Dobrze zadeklarowałem procesor. I jest on sprawny. Program jest jeszcze rozbudowany obsługę UART i generowane są przerwania. Najgorsze jest to że działa wszystko oprócz obsługi karty. Już nie mam pojęcia gdzie szukać błędu
  • #8 7326002
    sepako
    Poziom 14  
    Przy obsłudze SD-MMC korzystałem z tego źrodła http://www.ulrichradig.de/
    z inicjacją i obsługą w większości nie było problemów, ale zdarzały się karty praktycznie sprawne i podobne do pozostałych które jednak współpracować nie chciały. Może spróbuj innej karty.
  • #9 7326027
    grysek
    Poziom 19  
    Rzeczywiście kartę mam jakąś dziwną. Nie ma na niej nawet nazwy producenta. Ale jeśli byłaby uszkodzona to czytnik nie widziałby jej chyba nie?

    sepako w jakim języku pisałeś?
  • #10 7326035
    asembler
    Poziom 32  
    czy tu chodzi o karte czy raczej o ro ze SPI nie dziala skoro zawiesza sie na funkcji send_spi
    A moze trzeba zerowac flage SPIF tak juz głosno mysle:)
  • #11 7326362
    sepako
    Poziom 14  
    Problem polegał na tym że, karty które sprawdzałem wszystkie działały w czytniku do PC i wyglądały prawie identycznie, nie wszystkie działały te z wyjściem 7 pinowym. Pisałem w C, w bibliotece z której korzystałem zmieniłem tylko obsługę SPI na sprzętową.
  • #12 7327556
    grysek
    Poziom 19  
    asembler napisał:
    czy tu chodzi o karte czy raczej o ro ze SPI nie dziala skoro zawiesza sie na funkcji send_spi
    A moze trzeba zerowac flage SPIF tak juz głosno mysle:)


    Spróbuje sprawdzić czy działa SPI za pomocą drugiego procka, ale obawiam się że to właśnie karta nie odpowiada wogóle a SPI jest ok;/ O wpisywaniu czegokolwiek do SPIF można zapomnieć ponieważ jest to bit tylko do odczytu

    sepako, ale o co chodzi z tymi nóżkami? Przecież wszystkie karty MMC mają chyba 7 nie?
  • #13 7329380
    sepako
    Poziom 14  
    Są różne ja mam 7 i 13 wyprowadzeń ale to ma mniejsze znaczenie bo i tak w tego typu zastosowaniach korzysta sie z tych samych pinów. Co ciekawe karty 64MB z oznaczeniem MC(+10znakow) inicjowały się bez problemu natomiast o identycznej pojemności i wyglądzie z oznaczeniem HB(+10znakow) nie przechodziły inicjacji. Nie miałem też problemu z 512MB. Wszystkie oczywiście poprawnie wdziane są w czytniku. Ponieważ zaopatrzyłem sie w kilka sztuk nie wnikałem z jakiego powodu niektóre z nich nie dają się zainicjować.
  • #14 7329994
    grysek
    Poziom 19  
    Moja karta ma oznaczenie MC na początku więc z tego co mówisz powinna śmigać ;/

    Ale mam takie pytanko: Karta zwraca potwierdzenia tylko w trybie SPI? Wysyłając karcie 10 razy 0xFF po każdym razie procek oczekuje na odpowiedź od niej, a moze karta wtedy nie powinna nic wysyłać ponieważ nie pracuje w trybie SPI? może tu tkwi błąd?
  • #15 7330736
    sepako
    Poziom 14  
    To o czym piszesz u mnie wygląda tak
    
    for (unsigned char b = 0;b<0x0f;b++) //Wysyła min 74+ Takty na karty MMC/SD
        {
          mmc_write_byte(0xff);
        }
    

    W funkcji mmc_write_byte() tez mie ma zadnych procedur potwierdzenia wiec wniosek nasuwa sie sam.
  • #16 7332314
    grysek
    Poziom 19  
    Dodałem taką procedurę:
    mmc_on:
    out		SPDR, data
    in		acc,  SPSR
    sbrc		acc, WCOL
    rjmp		mmc_on
    ret
    


    Która tylko wysyła 0xFF, niestety nie pomogło;/ dodałem jeszcze sprawdzanie flagi WCOL gdyby SPI nie nadążało ale niestety dalej nie pomogło.

    Proszę jeszcze o jakieś rady. Zasilam to z USB, może powinienem na innym zasilaczu spróbować?
  • Pomocny post
    #17 7334442
    zbv
    Poziom 20  
    Ja to robię tak i wszystko działa może coś z tego wykorzystasz:
    
    loop_forever:
    	;////////////////// SD //////////////////
    	;SD‚na początek SPI na 400KHz wysylam 74 takty zegara
    	sbi		SD_DI		;koncowka na H
    	sbi		SD_CS
    	ldi		cnt, 100	;74 ­ takty
    sd_init_loop:
    	cbi		SD_CLK
    	ldi		r18, 20
    sd_init_wait1:
    	dec		r18
    	brne	sd_init_wait1
    	sbi		SD_CLK
    	ldi		r18, 20
    sd_init_wait2:
    	dec		r18
    	brne	sd_init_wait2
    	dec		cnt
    	brne	sd_init_loop
    
    	;CMD0‚ jak jest karta to ma odpowiedzieć 1
    	cbi		SD_CS
    	rcall	SDClearCommand
    	ldi		r18, 0
    	ldi		r23, 0x95
    	rcall	SDSendCommand
    
    	;teraz odpowiedz na CMD0 (ma być 1)‚
    	rcall	SDReceiveR1
    	mov		temp, r30
    ;-----------------------------
    ;-----------------------------
    	cpi		temp, 0x01
    	brne	loop_forever ; jak nie 1 to wracaj na początek
    ;-----------------------------
    ;-----------------------------
    
    	;SDv1 i MMC  CMD8 nie znają
    	;SDv2‚R1 00 00 01 AA ‚ i SDHC wiedzą co to CMD8 odpowiedz R1 prawidłowa to 1
    	clr		sdstate
    ;new_cmd8:
    	rcall	SDClearCommand; czyści rejestry r18..r23
    	ldi		r18, 8
    	ldi		r19, 0x00
    	ldi		r20, 0x00
    	ldi		r21, 0x01
    	ldi		r22, 0xAA
    	ldi		r23, 0x87
    	rcall	SDSendCommand
    	rcall	SDReceiveR1
    	mov		r8, r30
    ;----------------------------
    ;-----------------------------
    
    	mov		temp, r8
    	cpi		temp, 0x01
    	breq	sdv2	;sdv2 lub sdhc
    	rjmp    w_cmd41; karta to SDv1 lub MMC
    
    sdv2:
    ;------------------------
    ;------------------------
    ;Czytam OCR i ocr[2] ma być 1 i ocr[3] ma być 0xAA, dla kart sdv2 lub sdhc
    	rcall	SDReceiveByte
    	rcall	SDReceiveByte
    	rcall	SDReceiveByte
    	mov		r8, r30
    	rcall	SDReceiveByte
    	mov		r9, r30
    not_sdv2:
    
    	ldi		temp, 0x01
    	cp		r8, temp
    ; ma być ocr[2] i ocr[3] spelniony
    	ldi		temp, 0xAA
    	cpc		r9, temp
    	brne	PC+3      ;jeżeli nie spelniony warunek to przeskocz ustawianie sdstate
    	ldi		temp, 0b00000100 ;wpisz do sdstate że karta sdv2
    	mov		sdstate, temp    ;(na razie nie wiem czy może sdhc)
    ;-----------------------------
    ;-----------------------------
    w_cmd41:
    ldi r31,255 ; karta nie zawsze od razu odpowie więc trzeba paru prob
    ;------------------------------
    ;-----------------------------
    wait_cmd41r_loop:
    	;ACMD41 trzeba wyslac najpierw cmd55 i dopiero cmdACMD41
    ;------------------------------
    	ldi		r18, 255
    	rcall	SendClock
    ;------------------------------
    	rcall	SDClearCommand
    	ldi		r18, 55
    	rcall	SDSendCommand
    
    	ldi		r18, 255
    	rcall	SendClock
    
    	rcall	SDClearCommand
    	ldi		r18, 41
    	sbrc	sdstate, 2
    	ldi		r19, 0b01000000
    	rcall	SDSendCommand
    
    	;responce
    	rcall	SDReceiveR1
    
    	mov		r8, r30
    ;------------------------------
    ;-----------------------------
    	mov		r30, r8
    
    cpi r30,0x02
    ;brsh it_is_mmc3   ;skocz jeżeli r30>=2 (0,1- to znaczy że karta wie co jest grane) 
    brlo ccc1  ;skocz jesli r30 mniejsze niż 2
    ;	rjmp ccc1
    ;it_is_mmc3:
    	rjmp it_is_mmc ;to jest karta MMC
    
    ccc1:
    	;jakas karta SD
    	sbrc	r30, 0
    	rjmp	wait_cmd41r_loop
    
    ;-----------------------------
    	ldi		r18, 255
    	rcall	SendClock
    ;---------------------------
    	sbrs 	sdstate,2 ;jeżeli nie sd2 lub sdhc to przeskocz
    	rjmp	not_sdhc
    ;---------------------------
    wait_cmd58r_loop: ;sprawdzamy bit CCS w rejestrze OCR
    
    	rcall	SDClearCommand
    	ldi		r18, 58
    	rcall	SDSendCommand
    	rcall	SDReceiveR1
    	mov temp, r30
    	;-------------------------
    	;-------------------------
    	cpi temp,0x00  ;prawidłowa odpowiedz to 0
    	brne	wait_cmd58r_loop
    
    	rcall	SDReceiveByte ;ocr[0]
    	;--------------------------
    	andi	r30, 0x40
    	cpi 	r30,0x00  ; jezeli (OCR[0] and 0x40)>0 to karta sdhc
    	brne	go_sdhc
    	rjmp	not_sdhc
    ;----------------
    go_sdhc:
    	ldi		temp, 0b00000010 ;przypisuję bit SDHC w sdstate
    	or		sdstate, temp
    ;------------
    	;--------------------------
    	rcall	SDReceiveByte ;ocr[1]
    	;--------------------------
    	rcall	SDReceiveByte ;ocr[2]
    	;--------------------------
    	rcall	SDReceiveByte ;ocr[3]
    	;--------------------------
    	rjmp	not_sdhc
    ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
    it_is_mmc:
    	ldi 	r31,255
    	sbi		SD_CS
    	ldi		r18, 255
    	rcall	SendClock
    	cbi		SD_CS
    ;=========================
    ;------------------------
    it_is_mmc1:
    	clr		sdstate
    	rcall	SDClearCommand
    	ldi		r18, 1
    	ldi		r23, 0x95
    	rcall	SDSendCommand
    
    	;CMD1
    	rcall	SDReceiveR1
    	mov		temp, r30
    
    ;-----------------------------
    	cpi		temp, 0x00
    	breq	not_sdhc
    	dec  	r31
    	cpi		r31, 0x00
    	brne	it_is_mmc1
    ;+++++++++++++++++++++++++++++++++++++++++++++++++
    not_sdhc:
    
    ;----------------------------
    ;----------------------------	
    	ldi		r18, 255
    	rcall	SendClock
    ;----------------------------

    Dodałem znaczniki [code].
    [zumek]
  • #18 7338710
    grysek
    Poziom 19  
    Dzięki za kod. Spróbuje coś z tego wykorzystać :D napewno bardzo mi sie to przyda. A co z tym zasilaniem? z USB powinno wystarczyć czy nie bardzo?
    ...........
    To nie wina karty tylko SPI które nie wiedzieć czemu nie działa. Nie mam pojęcia czemu wogóle nie wysyła żadnych danych? Podobnie na wyjściu SCK nie pojawia się sygnał;/
    Sprawdzając działanie programu w symulacji AVR Studio okazuje się że w procedurze spi_init zaraz po wpisaniu danych do rejestru SPCR, bit MSTR sam się zeruje co by wyjaśniało brak sygnału na SCK.
    Czemu tak się dzieje? I jak to naprawić?

    Proszę o pomoc
    Posty scaliłem.
    [zumek]
  • Pomocny post
    #19 7345624
    zbv
    Poziom 20  
    Pin SS nawet niewykorzystany musi być ustawiony jako wyjście przy pracy SPI w trybie master.
  • #20 7346085
    grysek
    Poziom 19  
    Dzieki, teraz SPI już działa poprawnie. Wysyła komendy itd ale po wysłaniu CMD0 karta cały czas odpowiada wartościami 0xFF a powinna odpowiedzieć 1. Zupełnie tak jakbym MISO podpiął do plusa zasilania. Co może być jeszcze źle?

    Podaję kod programu po zmianach:

    
    ;--------------------* SPI *----------------------
    spi_init:
    ldi 		acc, (1<<MOSI) | (1<<SCK) | (1<<CS) | (1<<SS)
    out 		DDRB, acc
    ldi 		acc, (1<<SPE) | (1<<MSTR) 
    out 		SPCR, acc
    ret
    
    spi_send:
    out			SPDR, data
    in			acc,  SPSR
    sbrc		acc, WCOL
    rjmp		spi_send
    ret
    
    spi_receive:
    clr			data
    in			acc, SPSR
    sbrs  		acc,SPIF
    rjmp		spi_receive
    in			data, SPDR
    ret
    
    
    ;--------------------* MMC *----------------------
    mmc_init:
    rcall	spi_init
    sbi		PORTB, CS		;stan wysoki CS
    rcall	on_mmc
    cbi		PORTB, CS
    
    ldi		acc, 0
    sts		addr1, acc
    sts		addr2, acc
    sts		addr3, acc
    sts		addr4, acc
    
    CMD0:					;Przełącz karte w tryb SPI
    ldi		komenda, 0
    rcall	mmc_cmd
    rcall	mmc_read_R1
    mov		datau, data
    rcall	uart_zm
    ldi		datau, ' '
    rcall	uart_send
    cpi		data, 1
    brne	CMD0
    sbi		PORTC, LED1
    
    
    CMD1:						;Wyjdz ze stanu IDLE
    ldi		komenda, 1		
    rcall	mmc_cmd
    rcall	mmc_read_R1
    sbrc	data, IDLE
    rjmp	CMD1
    	
    ldi		datau, 'O'
    rcall	uart_send
    ldi		datau, 'K'
    rcall	uart_send
    ret
    
    mmc_cmd:
    ori		komenda, 0x40
    mov 	data, komenda
    rcall	spi_send
    lds		data, addr1
    rcall	spi_send
    lds		data, addr2
    rcall	spi_send
    lds		data, addr3
    rcall	spi_send
    lds		data, addr4
    rcall	spi_send
    ldi		data, 0x95 	
    ret
    
    
    mmc_read_R1:
    ldi		petla, 10
    read_loop:
     dec		petla
     breq		read_end
     ldi		data,0xFF
     rcall		spi_send
     rcall		spi_receive
    sbrc		data, BUSY
    rjmp 	read_loop
    read_end:
    ret
    
    
    on_mmc:
    ldi		petla, 10		;wyslij 80 cykli zegarowych
    on_loop:
       dec		petla
       breq		on_end
       ldi		data, 0xFF
       rcall	spi_send		;10 * 8 = 80
    rjmp	on_loop
    on_end:
    ret
  • Pomocny post
    #21 7349590
    zbv
    Poziom 20  
    Ja raczej bym zrobił tak:
    ;--------------------* MMC *----------------------
    mmc_init:
    rcall spi_init
    mmc_init1:
    sbi PORTB, CS ;stan wysoki CS
    rcall on_mmc
    cbi PORTB, CS

    ldi acc, 0
    sts addr1, acc
    sts addr2, acc
    sts addr3, acc
    sts addr4, acc

    CMD0: ;Przełącz karte w tryb SPI
    ldi komenda, 0
    rcall mmc_cmd
    rcall mmc_read_R1
    mov datau, data
    rcall uart_zm
    ldi datau, ' '
    rcall uart_send
    cpi data, 1
    brne mmc_init1
    sbi PORTC, LED1
  • #22 7350678
    grysek
    Poziom 19  
    Dziękuję za pomoc wszystkim! Problem był w tym co napisał zbv oraz w procedurze send_spi ponieważ powinienem sprawdzać flagę SPIF a nie WCOL.

    Szczególnie dziekuję koledze zbv.

    Problem rozwiązany!:D Pozdrawiam
REKLAMA