Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[SAM7X][C]Problem z sprintf

august_a 05 Dec 2010 20:53 2088 26
Computer Controls
  • #1
    august_a
    Level 21  
    Witam,
    Mam problem z funkcją sprintf, mianowicie:
    używam tej funkcji do formatowania danych aby wyświetlić je na lcd.
    Funkcja (niby) działa dobrze, ale po pewnym czasie zaczyna wyświetlać jakieś śmieci poza wartościami które wyświetla

    np.
    wyświetla datę: 10/11/201016036
    zamiast: 10/11/2010 itd...

    Dam przykład funkcji jak jej używam:
    
    char message[32]; 
    
    
    
    
    				sprintf((char*)message,"Czas: %02d:%02d:%02d",
    						(ptDS1337.hours),
    						ptDS1337.minutes, ptDS1337.seconds);
    				GLCD_Text(1,1,message);     
    				sprintf((char*)message,"Data: %d/%d/20%d",
    						ptDS1337.date,
    						ptDS1337.month,
    						ptDS1337.year);


    Co może być powodem?
  • Computer Controls
  • #3
    august_a
    Level 21  
    Quote:
    Powodem może być to co zwykle - zbyt mały stos nie wyrównany do 8 - tylko pierwsze, tylko drugie, albo obydwa.


    To w jaki sposób najlepiej to rozwiązać??
  • #4
    gaskoin
    Level 38  
    Zwiększyć stos, wyrównać go do 8, lub i to i to
  • #5
    august_a
    Level 21  
    Przesyłam zawartość pliku .s

    //------------------------------------------------------------------------------
    //         Headers
    //------------------------------------------------------------------------------
    
    #include "board.h"
    
    //------------------------------------------------------------------------------
    //         Definitions
    //------------------------------------------------------------------------------
    
    #define IRQ_STACK_SIZE   8*3*4
    
    #define ARM_MODE_ABT     0x17
    #define ARM_MODE_FIQ     0x11
    #define ARM_MODE_IRQ     0x12
    #define ARM_MODE_SVC     0x13
    
    #define I_BIT            0x80
    #define F_BIT            0x40
    
    //------------------------------------------------------------------------------
    //         Startup routine
    //------------------------------------------------------------------------------
    
                .align      4
                .arm
            
    /* Exception vectors
     *******************/
                .section    .vectors, "a"
    
    resetVector:
            ldr     pc, =resetHandler       /* Reset */
    undefVector:
            b       undefVector             /* Undefined instruction */
    swiVector:
            b       swiVector               /* Software interrupt */
    prefetchAbortVector:
            b       prefetchAbortVector     /* Prefetch abort */
    dataAbortVector:
            b       dataAbortVector         /* Data abort */
    reservedVector:
            b       reservedVector          /* Reserved for future use */
    irqVector:
            b       irqHandler              /* Interrupt */
    fiqVector:
                                            /* Fast interrupt */
    //------------------------------------------------------------------------------
    /// Handles a fast interrupt request by branching to the address defined in the
    /// AIC.
    //------------------------------------------------------------------------------
    fiqHandler:
            b       fiqHandler
    	
    //------------------------------------------------------------------------------
    /// Handles incoming interrupt requests by branching to the corresponding
    /// handler, as defined in the AIC. Supports interrupt nesting.
    //------------------------------------------------------------------------------
    irqHandler:
    
    /* Save interrupt context on the stack to allow nesting */
            sub     lr, lr, #4
            stmfd   sp!, {lr}
            mrs     lr, SPSR
            stmfd   sp!, {r0, lr}
    
    /* Write in the IVR to support Protect Mode */
            ldr     lr, =AT91C_BASE_AIC
            ldr     r0, [r14, #AIC_IVR]
            str     lr, [r14, #AIC_IVR]
    
    /* Branch to interrupt handler in Supervisor mode */
            msr     CPSR_c, #ARM_MODE_SVC
            stmfd   sp!, {r1-r3, r4, r12, lr}
            mov     lr, pc
            bx      r0
            ldmia   sp!, {r1-r3, r4, r12, lr}
            msr     CPSR_c, #ARM_MODE_IRQ | I_BIT
    
    /* Acknowledge interrupt */
            ldr     lr, =AT91C_BASE_AIC
            str     lr, [r14, #AIC_EOICR]
    
    /* Restore interrupt context and branch back to calling code */
            ldmia   sp!, {r0, lr}
            msr     SPSR_cxsf, lr
            ldmia   sp!, {pc}^
    
    //------------------------------------------------------------------------------
    /// Initializes the chip and branches to the main() function.
    //------------------------------------------------------------------------------
                .section    .text
                .global     entry
    
    entry:
    resetHandler:
    
    /* Dummy access to the .vectors section so it does not get optimized */
            ldr     r0, =resetVector
    
    /* Set pc to actual code location (i.e. not in remap zone) */
    	    ldr     pc, =1f
    
    /* Perform low-level initialization of the chip using LowLevelInit() */
    1:
            ldr     r4, =_sstack
            mov     sp, r4
    	    ldr     r0, =LowLevelInit
            mov     lr, pc
            bx      r0
    
    /* Initialize the relocate segment */
    
            ldr     r0, =_efixed
            ldr     r1, =_srelocate
            ldr     r2, =_erelocate
    1:
            cmp     r1, r2
            ldrcc   r3, [r0], #4
            strcc   r3, [r1], #4
            bcc     1b
    
    /* Clear the zero segment */
    	    ldr     r0, =_szero
            ldr     r1, =_ezero
            mov     r2, #0
    1:
            cmp     r0, r1
            strcc   r2, [r0], #4
            bcc     1b
    
    /* Setup stacks
     **************/
    /* IRQ mode */
            msr     CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT
            mov     sp, r4
            sub     r4, r4, #IRQ_STACK_SIZE
    
    /* Supervisor mode (interrupts enabled) */
            msr     CPSR_c, #ARM_MODE_SVC | F_BIT
            mov     sp, r4
    
    /* Branch to main()
     ******************/
            ldr     r0, =main
            mov     lr, pc
            bx      r0
    
    /* Loop indefinitely when program is finished */
    1:
            b       1b
    
    


    Tak mam teraz.
  • Computer Controls
  • #7
    august_a
    Level 21  
    /*------------------------------------------------------------------------------
     *      Linker script for running in internal Flash on the AT91SAM7X512.
     *----------------------------------------------------------------------------*/
    
    OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
    OUTPUT_ARCH(arm)
    ENTRY(entry)
    
    MEMORY
    {
        sram (W!RX) : ORIGIN = 0x200000, LENGTH = 0x20000
        flash (RX) : ORIGIN = 0x100000, LENGTH = 0x80000
    }
    
    SECTIONS
    {  
        .fixed :
        {
            . = ALIGN(4);
            _sfixed = .;
            *(.text*)
            *(.rodata*)
            . = ALIGN(4);
            _efixed = .;
        } >flash
    
        .relocate : AT (_efixed)
        {
            . = ALIGN(4);
            _srelocate = .;
            *(.vectors)
            *(.ramfunc)
            *(.data)
            . = ALIGN(4);
            _erelocate = .;
        } >sram
    
        .bss (NOLOAD) : {
            _szero = .;
            *(.bss)
            . = ALIGN(4);
            _ezero = .;
        } >sram
        
        _sstack = 0x220000;
    }
    end = .;


    A to jest mój skrypt linkera.
  • #8
    Freddie Chopin
    MCUs specialist
    No dobra, stos jest wyrównany i ten dla głównego programu jest "dosyć" spory. Teraz tylko powiedz jeszcze czy funkcje tą wywołujesz w przerwaniu czy w programie głównym, no i czy masz przerwania, a jeśli tak, to czy aby na pewno 96 bajtów na ich stos jest wystarczające...

    4\/3!!
  • #9
    august_a
    Level 21  
    Funkcja jest wyświetlana w pętli głównej.
    Ogólnie z przerwań korzystam: dla obsługi encodera, PIT, EMAC.
  • #10
    Freddie Chopin
    MCUs specialist
    No to zwiększ stos, bo 96 bajtów to tyle co nic dla takiego układu, a jeszcze masz przerwania zagnieżdżone. Mając 128kB pamięci SRAM naprawdę nie ma sensu się ograniczać w tej ważnej kwestii. Pamiętaj, żeby wielkość ta byłą podzielna przez 8.

    4\/3!!
  • #11
    august_a
    Level 21  
    Zwiększyłem stos dla przerwań
    #define IRQ_STACK_SIZE   8*32
    
    i nadal wywala jakieś śmieci.

    Jak mogę zwiększyć stos dla programu głównego?
  • #12
    Freddie Chopin
    MCUs specialist
    Stos dla programu głównego jest w Twojej konfiguracji całą resztą pamięci. Używasz dynamicznej alokacji? No a poza tym to zwiększyłeś go ledwo dwukrotnie - masz przecież 128kB pamięci - możesz na ten cel spokojnie wywalić kilka kilobajtów, a nie nędzne 256B - zwłaszcza gdy szukasz błędów.

    Ta zmienna do której zapisujesz ciąg znaków jest automatyczna czy statyczna? Spróbuj "odwrotnie" - zobaczysz czy coś to da.

    No i zawsze możesz załapać uproszczoną wersję sprintfa z mojej stronki - definitywnie mniejszą niż ten potwór z newliba.

    4\/3!!
  • #13
    gaskoin
    Level 38  
    aleś zwiększył :) weź tam wpakuj z kilobajt chociaż
  • #14
    august_a
    Level 21  
    Stos zwiększałem do 64k, i nadal nic nie pomogło. Zauważyłem jeszcze jedno. Czasami program główny się wiesza, ale przerwania działają.
  • #15
    directx11
    Level 17  
    A może to nie problem przerwań czy stosu a po prostu wystarczy dodać "\n" na końcu stringu podczas formatowania? I równocześnie wyczyścić bufor za pomocą memset() przed formatowaniem? Nie wiem do końca jak to jest w przypadku jednoukładowych (implementacja sprintf), ale praktyka tutaj powinna być chyba podobna do tej z PC?
  • #17
    directx11
    Level 17  
    Zależy jak wygląda procka do wyświetlania danych. Może akurat leci po znakach i czeka na koniec stringu w postaci "\n"? Bufor jest 32 znakowy jak widać z kawałka kodu, data nie obejmuje wszystkiego, więc może pojawiają się śmieci na końcu? No chyba, że ta implementacja sprintfa faktycznie sobie z tym radzi z automatu, ale to trzeba by zobaczyć w źródłach.
  • #18
    Freddie Chopin
    MCUs specialist
    Żaden printf() czy sprintf() nigdy nie czeka na koniec ciągu w postaci '\n' - co najwyżej na PC w printf() buforowanie może przytrzymać ciąg wyjściowy aż do otrzymania pełnej linii, ale to raczej nie printf(), tylko funkcje systemu operacyjnego.

    4\/3!!
  • #19
    directx11
    Level 17  
    Nie napisałem, że sprintf czeka, tylko funkcja do wyświetlania znaków - to chyba mała różnica? sprintf z tego co widać działa, tylko coś, co ten string pokazuje nie bardzo sobie radzi. Dobrze by było wiedzieć co.
  • #20
    User removed account
    User removed account  
  • #21
    august_a
    Level 21  
    Ponieważ ten sam wyświetlacz i tą samą bibliotekę używałem do AVR i wszystko śmigało.
  • #22
    User removed account
    User removed account  
  • #23
    nsvinc
    Level 35  
    O co wojna?
    IMHO uzywanie sprintfa w pokazany sposób to igranie z ogniem, w szczególności wtedy, jak ktos sprawia wrażenie że nie wie co robi.
    Brak zera w "message" po wykonaniu sprintfa (powody: za mala tablica, za maly stos, ...) skonczy sie tym, że funkcja przeszukująca tablicę wynikową będzie gonić znak po znaku DO ZERA, a gdzie ono jest, to hgw...:]

    Ja uzywam przerobionego printfa, ktory "printuje na wyswietlacz", i zero problemów. A jeśli nie chce się używać ciężkich funkcji, można użyc kilku funkcji prostych typu lcdstr, lcdint, lcdchar, lcd.... i poskladac z nich finalny napis.

    Do autora tematu:
    Sprawdź debuggerem co znajduje sie w tablicy "message" po wykonaniu sprintfa. Powinienes widziec tekst zakonczony ZEREM (null, #0 ). Jeśli w tej tablicy nie ma zera, nie masz co liczyć na prawidłowe wyświetlenie tego...
  • #24
    nenpa8lo
    Level 17  
    Sporo ludzi zapomina ze w mikroprocesorach zadeklarowanie bufora[8] oznacza dlugosc 8 i kropka. W PC system operacyjny zawsze doda \0 za osmym znakiem, co moze sugerowac ze bufor ma 9 znakow. Pisze bo sam przy przejsciu lata temu sie na to nadzialem :)
  • #25
    nsvinc
    Level 35  
    What?!

    Śmiesz twierdzić, że char tablica[8] na PC ma wielkosc 9 bajtow a na nie-PC juz 8?
    To jest chyba troche niezgodne z standardem....
  • #26
    directx11
    Level 17  
    nenpa8lo wrote:
    Sporo ludzi zapomina ze w mikroprocesorach zadeklarowanie bufora[8] oznacza dlugosc 8 i kropka. W PC system operacyjny zawsze doda \0 za osmym znakiem, co moze sugerowac ze bufor ma 9 znakow. Pisze bo sam przy przejsciu lata temu sie na to nadzialem :)


    A skąd kolego takie coś "wytrzasnąłeś"...
  • #27
    nenpa8lo
    Level 17  
    cofam glupote ktora palnolem :) Wlasnie przetestowalem i macie racje. A ja pamietam jak lata temu babka mowila ze jak zadeklarujesz bufor na PC to OS wstawi ci automatycznie \0 na koncu....