32-Bit-Ganzzahl ohne Vorzeichen in 8-Bit-BCD in AVR ASM für ATtiny. Wie kann man es effizienter machen?

Ich habe in AVR ein Programm geschrieben , um binäre Zahlen ohne Vorzeichen in Dezimalzahlen ASMumzuwandeln , basierend auf dem . (Ich weiß, das ist mehr als 8-stellig, aber ich brauche nur 8.)32-bit8 digitshift-add-332-bit

Der 32-bitEingang ist in R16-R19(Low-High).

Die 8 digitAusgabe erfolgt in R20-R24(Low-High), 2 Zahl/Byte, eine im Lower Nibble, eine im Higher Nibble.

Mein Problem: Es dauert ~ 1500 Zyklen, um eine 16-bitZahl zu berechnen, und ~ 2000 Zyklen, um eine zu berechnen 32-bit.

Kann mir jemand eine schnellere, professionellere Methode dafür vorschlagen? Das Ausführen eines Verfahrens mit 2000 Zyklen auf einem ATtiny bei 32,768 Khzist etwas, mit dem ich mich nicht wohl fühle.

Speichernutzungskarte:

Speicherbelegung für BinaryToBCD

Definitionen:

.def    a0  =   r16
.def    a1  =   r17
.def    a2  =   r18
.def    a3  =   r19

.def    b0  =   r20
.def    b1  =   r21
.def    b2  =   r22
.def    b3  =   r23

.def    i   =   r24
.def    j   =   r25

Der Code:

BinaryToBCD:
    clr     b0
    clr     b1
    clr     b2
    clr     b3
    ldi     i,  32
    sts     0x0068, i       ;(SRAM s8)

BinaryToBCD_1:
    clc
    rol     a0
    rol     a1
    rol     a2
    rol     a3
    rol     b0
    rol     b1
    rol     b2
    rol     b3

    lds     i, 0x0068       ;(SRAM s8)
    dec     i
    sts     0x0068, i       ;(SRAM s8)
    brne    BinaryToBCD_2
    ret

BinaryToBCD_2:
    cpi     b0,     0
    breq    BinaryToBCD_3
    mov     i,      b0
    rcall   Add3ToNibbles
    mov     b0,     i

BinaryToBCD_3:
    cpi     b1,     0
    breq    BinaryToBCD_4
    mov     i,      b1
    rcall   Add3ToNibbles
    mov     b1,     i

BinaryToBCD_4:
    cpi     b2,     0
    breq    BinaryToBCD_5
    mov     i,      b2
    rcall   Add3ToNibbles
    mov     b2,     i

BinaryToBCD_5:
    cpi     b3,     0
    breq    BinaryToBCD_1
    mov     i,      b3
    rcall   Add3ToNibbles
    mov     b3,     i
    rjmp    BinaryToBCD_1


Add3ToNibbles:
    mov     j,      i
    andi    j,      0b00001111
    cpi     j,      5
    in      j,      SREG
    sbrs    j,      0
    subi    i,      -3

    mov     j,      i
    swap    j
    andi    j,      0b00001111
    cpi     j,      5
    in      j,      SREG
    sbrs    j,      0
    subi    i,      -48
    ret
Was ist mit einer Nachschlagetabelle und der Ausnutzung der Tatsache, dass sie dreieckig ist?
Warum nicht schnellere interne Oszillatoren verwenden?
Bitte erzählen Sie mir mehr über den Tisch und die "Dreieckigkeit", ich weiß nicht, was Sie meinen. Kann keinen schnelleren Osc verwenden, da dieser Chip auch Zeit und Datum verwaltet. 32768 ist die höchste Genauigkeit, damit brauche ich nur 16 * 2-Bit-Überlauf auf dem Timer.
@GáborDani Was ich meinte, war ein Array von Dezimalzahlen mit einem Byte pro Ziffer für alle 2 ^ n, wie (3,2,7,6,8), (1,6,3,8,4), ( 0,8,1,9,2). Dann geht man die einzelnen Bits der Binärzahl durch und addiert die Zahlen zu einem 8 Byte langen Array (ein Byte für jede Ziffer). Wenn Sie von Bit 31 auf 0 gehen, werden die Dezimalstellen kürzer, sodass weniger Additionen erforderlich sind (das meinte ich mit Dreieckigkeit).
Ich würde versuchen, es in c zu schreiben und mir die Ausgabe des Compilers ansehen (nicht vergessen, die Optimierung einzuschalten), um vielleicht ein paar Tricks zu lernen, die ich auf meinen eigenen Code anwenden kann
Das eigentliche q nicht beantworten. aber wie Golaz vorgeschlagen hat, sollte es möglich sein, den ATTiny mit einer höheren Taktfrequenz (unter Verwendung des internen Oszillators) zu betreiben und einen Timer mit 32k laufen zu lassen, um die Echtzeit zu verfolgen; Wenn Sie uns die Teilenummer mitteilen können, können wir das mit Sicherheit sagen.

Antworten (2)

Dies basiert auf Vennys Ansatz (Venny nannte es Triangulation), ausgedrückt auf einem "Pseudo-C":

uint32 x; // input variable to convert

w = { 2, 1, 4, 7, 4, 8, 3, 6, 4, 8 }; // 2^31
r = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // initial result = 0

for (i = 31; i >= 0; i --)
{
   if ( 2^i  AND x )  // is x's bit i up?
      add(r, w);      // if yes, 1 ASCII ADD and 9 ASCII ADD w/CARRY MAX
   divide(w, 2)       // 10 SHIFT RIGHT MAX
}

Routinen addieren und dividieren sind keine Erklärung erforderlich, imo.

Es gibt eine Reihe von Artikeln und Anwendungshinweisen zu diesem Thema. Beispiel: http://www.element14.com/community/servlet/JiveServlet/downloadBody/47820-102-3-258641/Cypress.Application_Notes_35.pdf