PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Mischung von Assembler und C



Siro
17.09.2020, 19:07
Hallo zusammen,

ich steuere grad mit dem PIC10F332 einen RGB-Stripe an.
Das fuktioniert auch schon ganz hervorragend, bin ganz begeistert.
Sein maximales Timing bekommt das grade so auf die Reihe.
Die Ausschiebefunktion musste ich jedoch in Assembler implementieren wegen der Laufzeit
und da taucht nun ein "kleines" Problemchen auf:

In der Ausschiebefunktion benötige ich auch die Anzahl der LEDs die ich mit
#define LED_COUNT 4
in "C" declariert habe.

Wie komme ich da aber ran innerhalb meiner Assembler Ausschiebefunktion ?

Natürlich kann ich in Assembler hier den Wert multipliziert mit 3 direkt ins Register laden,
aber dann muss ich bei Änderungen von LED_COUNT auch jedesmal den Assemblercode ändern,
das halte ich für eine "schlechte/unschöne" Programmierung.
....vegesse ich auch garantiert irgendwann wenn ich später mal Änderungen vornehme...;)


// Declaration einer einzelnen RGB LED
// Jede LED hat 3 Bytes, insgesamt also 24 Bits
typedef struct // __pack ? bei 8 Bittern unnötig, ist immer packed
{
U8 green; /* 8 Bit fuer die Helligkeit gruen */
U8 red; /* 8 Bit fuer die Helligkeit rot */
U8 blue; /* 8 Bit fuer die Helligkeit blau */
} TLed; /* Type Bezeichner ist TLed */

#define LED_COUNT 4 // Anzahl der anzusteuernden RGB Leds

TLed LedArray[LED_COUNT]; // gesamtes Datenarray der Ledkette
// dieses Array wird dann per Assmblercode ausgeschoben

//------------------------------------------------------------------------------
// Der Assembler-Code zum Ausschieben von LedArray:
// für 250ns Instruction Cycle Time 4 MHz
// PMDATL enthält das auszuschiebene Datenbyte für die WS2812 RGB-Led Kette
// wird also als Zwischenspeicher benutzt. (8 Bit Register)
// PMADRL wird für den Bytezähler benutzt (8 Bit Register)
// PMDATH wird als Bitzähler benutzt !!! ist nur ein 6 Bit Register
// das reicht aber, wir zählen ja nur von 8 bis 0

void asm_LedShiftOut(void)
{
asm("movlw LOW _LedArray"); // address of LedArray
asm("movwf FSR"); // to FSR index register

asm("movlw 12"); // <==== eigentlich LED_COUNT * 3) das geht aber nicht <======

asm("movwf PMADRL"); // use PMADRL as byteCount

asm("Label_NextByte:"); // !! WICHTIG, der Doppelpunkt ab XC8 V2.20 !!
asm("movlw 8"); // set bit count to 8
asm("movwf PMDATH"); // use PMDATH as Bitcounter
asm("movf INDF,W"); // load byte from LedArray to W register
asm("movwf PMDATL"); // save Databyte to PMDATL

asm("Label_ByteLoop:");
asm("btfsc PMDATL,7"); // scip if databit is clear (MSB)
asm("goto Label_High"); // else databit ist set
asm("bsf LATA,0"); // set WS2812 DataLine to High 250ns
asm("bcf LATA,0"); // set WS2812 DataLine to Low
asm("goto Label_nextBit");

asm("Label_High:"); // High Bit
asm("bsf LATA,0"); // set WS2812 DataLine to High
asm("NOP"); asm("NOP"); asm("NOP"); // hold Line High for 1000ns
asm("bcf LATA,0"); // set Line to Low

asm("Label_nextBit:");
asm("rlf PMDATL,F"); // databyte left
asm("decfsz PMDATH,F"); // bitCount-1, scip if all bits done
asm("goto Label_ByteLoop"); // next bit

asm("incf FSR,F"); // address pointer to next Led Byte
asm("decfsz PMADRL,F"); // byteCount-1 scip if all bytes done
asm("goto Label_NextByte"); // else send next byte

// __delay_us(100); // Das Ende der Datenübertragung erreicht wenn die Leitung länger als 50us Low bleibt.
// !!! mindestens 80us bei SK68 Leds

// hier brauche ich eigentlich nicht warten, weil der restliche Programmcode benötigt ja schon Zeit ???
asm("movlw 0x85"); // das sind 100us
asm("movwf PMDATL");
asm("Label_delay100:");
asm("decfsz PMDATL,F");
asm("goto Label_delay100");
}

Vielleicht habt Ihr eine Idee wie man das evtl. auch anders lösen kann.

Siro

White_Fox
17.09.2020, 20:59
Und wenn du LED_COUNT als Const deklarierst?

Das #define ist ja, soweit ich weiß, eine reine Präprozessoranweisung von der der Compiler nix mehr mitbekommt und die sich dann auch nicht im Programmcode niederschlagen dürfte.

Siro
18.09.2020, 01:03
Hallo White_Fox, ersteinmal Danke für die Rückmeldung, ich hab das grade mal probiert.

const LED_COUNT = 4; // hier meckert der Compiler mit einem Warning, das wäre ja nicht so schlimm
const int LED_COUNT = 4; // so ist der Warning weg. Aber es ist jetzt quasi eine initialisierte Variable.

TLed LedArray[LED_COUNT]; // damit ist dieses Konstrukt nicht mehr gültig. "variable length array not supported"

Eine Konstante muss ja irgendwie im Speicher abgelegt werden.
Das kann der Compiler vermutlich selbst enscheiden ob er das im RAM oder im Codebereich macht ??
Wenn ich const benutze habe ich anscheinend immer eine "Instanz" im RAM und benötige Speicherplatz,
deshalb meckert der Compiler auch wenn ich die Typangabe weglasse, da er nicht weis wieviel Speicher er benötigt,
somit reserviert er einen "int".

Wie dem auch sei, ein Array benötigt einen "festen" Wert für die Größenangabe.
Dieser feste Wert kann anscheinend nur eine Zahl bzw. ein #define sein ? (meine Vermutung)

Ein #define kennt dann aber der Assembler nicht mehr, wie Du schon schriebst, ist das für den Preprozessor.

Ich weis nicht ob man das irgendwie "übergreifend" declarieren kann.

- - - Aktualisiert - - -
--------------------------------------------

Guten Morgen, es hat mir keine Ruhe gelassen

Ich habe das Problem jetzt so gelöst:
Es gibt eine Variable in der die Grösse des Led Arrays gespeichert wird.
Diese wird vom Compiler selbst eingetragen


typedef struct
{
U8 green;
U8 red;
U8 blue;
} TLed;

#define LED_COUNT 4 // Anzahl der anzusteuernden RGB Leds

TLed LedArray[LED_COUNT]; // gesamtes Datenarray der Ledkette

// hier NEU: damit ich mit dem Assembler auf die Anazahl Bytes im LedArray zugreifen kann.
unsigned char ArraySize = sizeof(LedArray); // die Groesse des Arrays in Bytes


Auf diese Weise kann ich nun mit

asm("movf _ArraySize,W");

auf die Anzahl der Bytes des LedArrays zugreifen.
Nun brauche ich nur noch an einer Stelle, nämlich den Wert LED_COUNT ändern und die Assemblerfunktion macht es dann auch gleich richtig.