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

MMnet1002 AT91SAM9620 i ledblink.c

mrtip 10 Jun 2009 23:33 2939 4
Computer Controls
  • #1
    mrtip
    Level 14  
    Mam trochę problemów z tą platformą a szczególnie z jedną rzeczą która mnie mocno denerwuje - brak jakiegokolwiek wsparcia !!!

    Czekam na odpowiedź z Propoxu i wiem że niedługo się doczekam, ale dzisiaj poruszę to na forum.

    Mam nadzieję że ktoś rozwiązał problem , który mnie dręczy a mianowicie:
    - chciałbym sterować portami z częstotliwością rzędu 200 khz.

    Nie interesują mnie rozwiązania z basha bo jest okropnie wolny. A jedynie rozwiązania kompilowane w C++.

    Na początek zaczynam od mrugania diodą ale niestety tu zaczynają się schody bo w Linuxie dostęp do fizycznej warstwy jest okropnie ciężki.
    Z dołączonych źródeł OpenWrt niewiele można wywnioskować.

    kawałek zmiennych z pliku: ledblink.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <sys/mman.h>

    #define MAP_SIZE 4096UL /* the size of one page of virtual memory */
    #define MAP_MASK (MAP_SIZE - 1) /* mask used for the one page of virtual memory */

    #define GPIOF_CON 0x56000050 /* physical address of the GPIO F control register */
    #define GPIOF_DAT 0x56000054 /* physical address of the GPIO F data register */


    Zaznaczyłem złe adresy bo nie wiem do końca jakie określić dla at91

    A at91 jest coś w tym stylu:


    /*
    * System Peripherals (offset from AT91_BASE_SYS)
    */
    #define AT91_PIOA (0xfffff400 - AT91_BASE_SYS) /* PIO Controller A */
    #define AT91_PIOB (0xfffff600 - AT91_BASE_SYS) /* PIO Controller B */
    #define AT91_PIOC (0xfffff800 - AT91_BASE_SYS) /* PIO Controller C */
    #define AT91_PIOD (0xfffffa00 - AT91_BASE_SYS) /* PIO Controller D */


    Adresy pinów PIO z pliku gpio.h

    #ifndef __ASM_ARCH_AT91RM9200_GPIO_H
    #define __ASM_ARCH_AT91RM9200_GPIO_H

    #include <asm/irq.h>

    #define PIN_BASE NR_AIC_IRQS

    #define MAX_GPIO_BANKS 5

    /* these pin numbers double as IRQ numbers, like AT91xxx_ID_* values */

    #define AT91_PIN_PA0 (PIN_BASE + 0x00 + 0) (i tak do)
    #define AT91_PIN_PA31 (PIN_BASE + 0x00 + 31)

    #define AT91_PIN_PB0 (PIN_BASE + 0x20 + 0) (i tak do)
    #define AT91_PIN_PB31 (PIN_BASE + 0x20 + 31)

    #define AT91_PIN_PC0 (PIN_BASE + 0x40 + 0) (i tak do)
    #define AT91_PIN_PC31 (PIN_BASE + 0x40 + 31)

    #define AT91_PIN_PD0 (PIN_BASE + 0x60 + 0) (i tak do)
    #define AT91_PIN_PD31 (PIN_BASE + 0x60 + 31)

    #define AT91_PIN_PE0 (PIN_BASE + 0x80 + 0) (i tak do)
    #define AT91_PIN_PE31 (PIN_BASE + 0x80 + 31)

    #ifndef __ASSEMBLY__
    /* setup setup routines, called from board init or driver probe() */
    extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup);
    extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
    extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
    extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
    extern int __init_or_module at91_set_gpio_output(unsigned pin, int value);
    extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on);
    extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on);

    /* callable at any time */
    extern int at91_set_gpio_value(unsigned pin, int value);
    extern int at91_get_gpio_value(unsigned pin);

    /* callable only from core power-management code */
    extern void at91_gpio_suspend(void);
    extern void at91_gpio_resume(void);

    /*-------------------------------------------------------------------------*/

    /* wrappers for "new style" GPIO calls. the old AT91-specfic ones should eventually be removed (along with this errno.h inclusion), and the gpio request/free calls should probably be implemented. */

    #include <asm/errno.h>

    static inline int gpio_request(unsigned gpio, const char *label)
    {
    return 0;
    }

    static inline void gpio_free(unsigned gpio)
    {
    }

    extern int gpio_direction_input(unsigned gpio);
    extern int gpio_direction_output(unsigned gpio, int value);

    static inline int gpio_get_value(unsigned gpio)
    {
    return at91_get_gpio_value(gpio);
    }

    static inline void gpio_set_value(unsigned gpio, int value)
    {
    at91_set_gpio_value(gpio, value);
    }

    #include <asm-generic/gpio.h> /* cansleep wrappers */

    static inline int gpio_to_irq(unsigned gpio)
    {
    return gpio;
    }

    static inline int irq_to_gpio(unsigned irq)
    {
    return irq;
    }

    #endif /* __ASSEMBLY__ */

    #endif


    Rejestry jednego PINu z pliku at91_pio.h

    #ifndef AT91_PIO_H
    #define AT91_PIO_H

    #define PIO_PER 0x00 /* Enable Register */
    #define PIO_PDR 0x04 /* Disable Register */
    #define PIO_PSR 0x08 /* Status Register */
    #define PIO_OER 0x10 /* Output Enable Register */
    #define PIO_ODR 0x14 /* Output Disable Register */
    #define PIO_OSR 0x18 /* Output Status Register */
    #define PIO_IFER 0x20 /* Glitch Input Filter Enable */
    #define PIO_IFDR 0x24 /* Glitch Input Filter Disable */
    #define PIO_IFSR 0x28 /* Glitch Input Filter Status */
    #define PIO_SODR 0x30 /* Set Output Data Register */
    #define PIO_CODR 0x34 /* Clear Output Data Register */
    #define PIO_ODSR 0x38 /* Output Data Status Register */
    #define PIO_PDSR 0x3c /* Pin Data Status Register */
    #define PIO_IER 0x40 /* Interrupt Enable Register */
    #define PIO_IDR 0x44 /* Interrupt Disable Register */
    #define PIO_IMR 0x48 /* Interrupt Mask Register */
    #define PIO_ISR 0x4c /* Interrupt Status Register */
    #define PIO_MDER 0x50 /* Multi-driver Enable Register */
    #define PIO_MDDR 0x54 /* Multi-driver Disable Register */
    #define PIO_MDSR 0x58 /* Multi-driver Status Register */
    #define PIO_PUDR 0x60 /* Pull-up Disable Register */
    #define PIO_PUER 0x64 /* Pull-up Enable Register */
    #define PIO_PUSR 0x68 /* Pull-up Status Register */
    #define PIO_ASR 0x70 /* Peripheral A Select Register */
    #define PIO_BSR 0x74 /* Peripheral B Select Register */
    #define PIO_ABSR 0x78 /* AB Status Register */
    #define PIO_OWER 0xa0 /* Output Write Enable Register */
    #define PIO_OWDR 0xa4 /* Output Write Disable Register */
    #define PIO_OWSR 0xa8 /* Output Write Status Register */


    Jeszcze jedna dana do zrozumienia PIO


    #ifndef __ASM_ARCH_IRQS_H
    #define __ASM_ARCH_IRQS_H

    #include <asm/io.h>
    #include <asm/arch/at91_aic.h>

    #define NR_AIC_IRQS 32


    /*
    * Acknowledge interrupt with AIC after interrupt has been handled.
    * (by kernel/irq.c)
    */
    #define irq_finish(irq) do { at91_sys_write(AT91_AIC_EOICR, 0); } while (0)


    /*
    * IRQ interrupt symbols are the AT91xxx_ID_* symbols
    * for IRQs handled directly through the AIC, or else the AT91_PIN_*
    * symbols in gpio.h for ones handled indirectly as GPIOs.
    * We make provision for 5 banks of GPIO.
    */
    #define NR_IRQS (NR_AIC_IRQS + (5 * 32))

    /* FIQ is AIC source 0. */
    #define FIQ_START AT91_ID_FIQ

    #endif


    Podałem dość wyczerpującą dokumentację by nawet napisać w asemblerze procedurę odczytu czy zapisu do portu. Ale nie wiem jak mam to ugryść. Potrzebuję więc pomocy.

    Poniżej podaję link z rozwiązaniem kogoś kto sobie zaczął mrugać
    http://www.tincantools.com/assets/Ledblink.c
    Dodam że ledblink.c kompiluje mi się bez zarzutu ale niestety nie działa na MMnet1002 po zmianie adresów ze źródeł powyżej.
  • Computer Controls
  • #2
    Kalvis
    Level 13  
    Najlepiej zrobić to poprzez sterownik gpio_dev. Mam specjalnego Pacha do tego celu. Wymagana jest kompilacja ponowna kompilacja kernela, chyba że skompiluje się go jako moduł. Więcej napisze jeśli problem nadal aktualny.
  • Computer Controls
  • #3
    mrtip
    Level 14  
    Witaj Kalvis!
    Że się tak wyrażę porzuciłem temat MMNet1002 ponieważ mocno mnie zdenerwowało przekompilowywanie procedur na ARM. Wziąłem kupiłem miniITX zasilacz z carPC i mam architekturę PC i proc Intela.
    Tak wogóle to temat jest nadal mocno aktualny, bo warto wrócić do urządzeń opartych o architekturę ARM i tworzyć zespół wspólnej adoracji :)
  • #4
    jereq
    Level 10  
    Choć ten wątek jest stary jak świat to postanowiłem dodać swoje, działające rozwiązanie (miganie PC0 co sekundę):

    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    #define PIOA_BASE 0xFFFFF000 // adresy wskazujące na port C
    #define off 0x0800
    
    #define PIO_OER        0x10    /* Output Enable Register */
    #define PIO_PER        0x00    /* Enable Register */
    #define PIO_PUDR    0x60    /* Pull-up Disable Register */
    #define PIO_SODR    0x30    /* Set Output Data Register */
    #define PIO_CODR    0x34    /* Clear Output Data Register */
    #define PA31 31
    volatile unsigned int *A_OER, *A_PER, *A_PUDR, *A_SODR, *A_CODR;
    
    unsigned char *start;
    
    int main(void){
    
      int fd = open("/dev/mem", O_RDWR|O_SYNC);
      if(fd<0){
              printf("memory descriptor error");
              exit(-1);
              }
      start = (unsigned char *)mmap(0, getpagesize(), PROT_READ|PROT_WRITE,
    MAP_SHARED, fd, PIOA_BASE);
    
      A_OER = (unsigned int *)(start +off+ PIO_OER);
      A_PER = (unsigned int *)(start +off+ PIO_PER);
      A_PUDR = (unsigned int *)(start +off+PIO_PUDR);
      A_SODR = (unsigned int *)(start +off+ PIO_SODR);
      A_CODR = (unsigned int *)(start +off+ PIO_CODR);
    
      *A_OER = 0x01; // PC0 jako wyjście
      *A_PER = 0x01; // /* Enable PIOC control on the pin*/
      *A_PUDR = 0x01; // Odłączenie rezystora pull-up
    
      for(int i=0;i<60;i++){
               *A_SODR = 0x01; // PC0 w stan wysoki
      sleep(1);
               *A_CODR = 0x01; // PC0 w stan niski
      sleep(1);
    }
    
      exit(0);
    
    }
    


    Mam nadzieję, że komuś się to jeszcze przyda :)
  • #5
    wawer_rz
    Level 10  
    Witam,
    Od kilku dni mam do czynienia z MMnet1002. Mam problem bo nie mam zielonego pojęcia jak w c lub c++ odczytywać w pętli stan wejścia(nie zależy mi na szybkości proces to 3 uderzenia,impulsy na wejście, na 1s max). Dodam że google już odwiedzone wielokrotnie tak samo jak to forum. W dokumentacji http://www.kernel.org/doc/Documentation/gpio.txt znalazłem coś takiego:
    int gpio_get_value(unsigned gpio);
    Jak tego należy użyć? Czy int gpio_get_value(gpioN) gdzie N to numer portu i czy to w ogóle ruszy. Kolejne pytanie jakie biblioteki należy dołączyć do include aby można było wykorzystać wyżej wymienione funkcje? Albo jak użyć /sys/class/gpio/gpioN/value ?