forum.mcontrollers.com - hlavní stránka forum.mcontrollers.com - fórum

 

.: fórum - hlavní stránka :.
Technology Stronghold by Rudolf Vesely
How to build Microsoft System Center hosted cloud series
FAQFAQ HledatHledat Seznam uživatelůSeznam uživatelů Uživatelské skupinyUživatelské skupiny RegistraceRegistrace
ProfilProfil StatistikaStatistika Soukromé zprávySoukromé zprávy PřihlášeníPřihlášení

 
Ovládání Led pásku - PORTG

 
Přidat nové téma   Zaslat odpověď    Obsah fóra mcontrollers.com -> AVR
 
DragonSoul
Profesionál
Profesionál


Založen: 4.3.2010
Příspěvky: 523
Bydliště: Praha

PříspěvekZaslal: 24 listopad 2019, 22:47    Předmět: Ovládání Led pásku - PORTG Citovat

Přeji hezký večer.
Hraji si s programovatelnými RGB Pololu LED páskami, kdde posláním 24-bit adresy se zvolí barva LED.
Knihovnu jsem se snažil napsat, ale nejsem tak dobrý, tak jsem nějakou stáhnul.
Funguje velice dobře až na jednu věc.
Používám ATMEGA64 a když to zkouším použít pro PORTA,B,C,D,E tak to funguje ale pro porty F a G ne.
Dočetl jsem se, že porty F a G jsou v takzvaných extended registrech, ale nevím jak to v knihovně změnit aby to fungovalo.
Zde je funkce, která to zpracovává.

kód:

/** The rgb_color struct represents the color for an 8-bit RGB LED.
    Examples:
      Black:      (rgb_color){ 0, 0, 0 }
      Pure red:   (rgb_color){ 255, 0, 0 }
      Pure blue: (rgb_color){ 0, 255, 0 }
      Pure green:  (rgb_color){ 0, 0, 255 }
      White:      (rgb_color){ 255, 255, 255} */
typedef struct rgb_color
{
  unsigned char red, green, blue;
} rgb_color;

/** led_strip_write sends a series of colors to the LED strip, updating the LEDs.
 The colors parameter should point to an array of rgb_color structs that hold the colors to send.
 The count parameter is the number of colors to send.
 This function takes about 1.1 ms to update 30 LEDs.
 Interrupts must be disabled during that time, so any interrupt-based library
 can be negatively affected by this function.
 Timing details at 20 MHz (the numbers slightly different at 16 MHz and 8MHz):
  0 pulse  = 400 ns
  1 pulse  = 850 ns
  "period" = 1300 ns
 */
void __attribute__((noinline)) led_strip_write(rgb_color * colors, unsigned int count)
{
  // Set the pin to be an output driving low.
  LED_STRIP_PORT &= ~(1<<LED_STRIP_PIN);
  LED_STRIP_DDR |= (1<<LED_STRIP_PIN);

  cli();   // Disable interrupts temporarily because we don't want our pulse timing to be messed up.
  while(count--)
  {
    // Send a color to the LED strip.
    // The assembly below also increments the 'colors' pointer,
    // it will be pointing to the next color at the end of this loop.
    asm volatile(
        "ld __tmp_reg__, %a0+\n"
        "ld __tmp_reg__, %a0\n"
        "rcall send_led_strip_byte%=\n"  // Send red component.
        "ld __tmp_reg__, -%a0\n"
        "rcall send_led_strip_byte%=\n"  // Send green component.
        "ld __tmp_reg__, %a0+\n"
        "ld __tmp_reg__, %a0+\n"
        "ld __tmp_reg__, %a0+\n"
        "rcall send_led_strip_byte%=\n"  // Send blue component.
        "rjmp led_strip_asm_end%=\n"     // Jump past the assembly subroutines.

        // send_led_strip_byte subroutine:  Sends a byte to the LED strip.
        "send_led_strip_byte%=:\n"
        "rcall send_led_strip_bit%=\n"  // Send most-significant bit (bit 7).
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"
        "rcall send_led_strip_bit%=\n"  // Send least-significant bit (bit 0).
        "ret\n"

        // send_led_strip_bit subroutine:  Sends single bit to the LED strip by driving the data line
        // high for some time.  The amount of time the line is high depends on whether the bit is 0 or 1,
        // but this function always takes the same time (2 us).
        "send_led_strip_bit%=:\n"
#if F_CPU == 8000000
        "rol __tmp_reg__\n"                      // Rotate left through carry.
#endif
        "sbi %2, %3\n"                           // Drive the line high.

#if F_CPU != 8000000
        "rol __tmp_reg__\n"                      // Rotate left through carry.
#endif

#if F_CPU == 16000000
        "nop\n" "nop\n"
#elif F_CPU == 20000000
        "nop\n" "nop\n" "nop\n" "nop\n"
#elif F_CPU != 8000000
#error "Unsupported F_CPU"
#endif

        "brcs .+2\n" "cbi %2, %3\n"              // If the bit to send is 0, drive the line low now.

#if F_CPU == 8000000
        "nop\n" "nop\n"
#elif F_CPU == 16000000
        "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
#elif F_CPU == 20000000
        "nop\n" "nop\n" "nop\n" "nop\n" "nop\n"
        "nop\n" "nop\n"
#endif

        "brcc .+2\n" "cbi %2, %3\n"              // If the bit to send is 1, drive the line low now.

        "ret\n"
        "led_strip_asm_end%=: "
        : "=b" (colors)
        : "0" (colors),         // %a0 points to the next color to display
          "I" (_SFR_IO_ADDR(LED_STRIP_PORT)),   // %2 is the port register (e.g. PORTC)
          "I" (LED_STRIP_PIN)     // %3 is the pin number (0-8)
    );

    // Uncomment the line below to temporarily enable interrupts between each color.
    //sei(); asm volatile("nop\n"); cli();
  }
  sei();          // Re-enable interrupts now that we are done.
  _delay_us(80);  // Send the reset signal.
}
           


Chyba je určitě v tomto
kód:

         "I" (_SFR_IO_ADDR(LED_STRIP_PORT)),   // %2 is the port register (e.g. PORTC)
          "I" (LED_STRIP_PIN)     // %3 is the pin number (0-8)

Pomůžete prosím?

_________________
Hodne se ucim (delam hodne chyb).
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Balů
Profesionál
Profesionál


Založen: 29.10.2012
Příspěvky: 789

PříspěvekZaslal: 24 listopad 2019, 23:35    Předmět: Citovat

To znamená, že k těmto portům nepřistupuješ pomocí IO instrukcí (in, out, sbi, cbi), ale pracuješ s nimi jako s RAM pamětí.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
DragonSoul
Profesionál
Profesionál


Založen: 4.3.2010
Příspěvky: 523
Bydliště: Praha

PříspěvekZaslal: 25 listopad 2019, 9:47    Předmět: Citovat

To je hezké.
Zkoušel jsem tu funkci přepsat do C, ale evidentně to neumím napsat tak, aby to mělo to správné časování.
Zkoušel jsem to přes přerušení od časovače, dokonce jsem použil i _delay_us, ale pásek jsem sám nerozběhl.
Poradíte prosím, jak tu funkci přepsat tak aby to fungovalo i pro PortF a G?
Předpokládám, že se změní počet cyklů a bude se tam muset ještě něco upravit, ale na to už mé znalosti nestačí.

_________________
Hodne se ucim (delam hodne chyb).
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Balů
Profesionál
Profesionál


Založen: 29.10.2012
Příspěvky: 789

PříspěvekZaslal: 26 listopad 2019, 9:41    Předmět: Citovat

Jde o to nahradit instrukce SBI a CBI instrukcí ST a mělo by to být univerzální pro použití pro porty jak na extended registrech, tak na standartních, protože i k portům na standartních registrech lze přistoupit pomocí adresace přes paměť. S časováním by moc velký problém být neměl, protože oboje instrukce trvají 2 takty hodin. Jediné, co musíš udělat je předat adresu portu do některého z dvojregistrů (X, Y, Z) a připravit si hodnoty portu pro vynulování a nastavení daného bitu, protože CBI a SBI pracují s bitem a neovlivňují zbytek portu, kdežto ST zapisuje do celého portu. Nejsem kovaný v použití inline assembleru v Cčku, takže Ti tady ukážu, jak by měl assemblerovský zápis vypadat a snad Ti někdo poradí, jak to přelouskat do inline assembleru.

Příklad pro použití s dvojregistrem Z :

kód:
ldi ZH, high(PametovaAdresaPortu)       ; ZH asi bude vždy 0x00
ldi ZL, low(PametovaAdresaPortu)
ldi TempRegistr, (1<<PozadovanyBit)     ; TempRegistr musí být R16 až R32, kromě použitých pro adresu portu.
mov NulovaciRegistr, TempRegistr        ; Registr, ve kterém bude hodnota, která se zapíše místo instrukce CBI
mov NastavovaciRegistr, TempRegistr     ; Registr, ve kterém bude hodnota, která se zapíše místo instrukce SBI
ld TempRegistr, Z                       ; Načtení aktuální hodnoty portu
or NastavovaciRegistr, TempRegistr
eor NulovaciRegistr, NastavovaciRegistr ; V tuhle chvíli je připraveno vše k nahrazení instrukcí CBI a SBI

To byla příprava před vlastní smyčkou. Tu provedeš jenom jednou na začátku.

Ve vlastní smyčce :
kód:
cbi %2, %3
nahradíš instrukcí
st Z, NulovaciRegistr

sbi %2, %3
nahradíš instrukcí
st Z, NastavovaciRegistr


Assembler není problém, ale do jeho inline použití jsem zatím nějak neproniknul, ale snad jsem Tě alespoň nasměroval.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

Zobrazit příspěvky z předchozích:   
Zobrazit předchozí téma :: Zobrazit následující téma  
Přidat nové téma   Zaslat odpověď    Obsah fóra mcontrollers.com -> AVR Časy uváděny v GMT + 2 hodiny
 
Strana 1 z 1
Přejdi na:  
Můžete přidat nové téma do tohoto fóra.
Můžete odpovídat na témata v tomto fóru.
Nemůžete upravovat své příspěvky v tomto fóru.
Nemůžete mazat své příspěvky v tomto fóru.
Nemůžete hlasovat v tomto fóru.
Můžete k příspěvkům připojovat soubory
Můžete stahovat a prohlížet přiložené soubory
 



Num Lock Holder - app to hold Numlock
Copyright © 2019 Rudolf Veselý, mcontrollers.com.
Je zakázáno používat části tohoto webu bez souhlasu autora. || Powered by phpBB © 2001, 2002 phpBB Group - with RedSquare DoubleJ(Jan Jaap)