Assembler RFN12b an Tiny44 und Tiny2313 via USI

dannyboy1994

Mitglied
14. Dez. 2016
60
0
6
29
Neumarkt i.d.OPF
Sprachen
  1. Assembler
Hallo community. Ich bin derzeit dabei mir eine kleine Wetterstation zu bauen, bei welcher mir ein tiny44 die außentemperatur und Luftfeuchtigkeit über ein RFM12 Modul senden soll. Ein Tiny2313 soll das Ganze dann auf einem LCD und über den USART ausgeben. Nun stehe ich gerade am Anfang des ganzen und versuche mir funktionstüchtige routinen zu schreiben. Einmal eine für den tiny(reiner empfänger) und einen für den tiny44(reiner sender)

Das Ganze soll der USI realisiert werden.
Hier einmal mein aktueller stand beim tiny2313 Empfänger. Das drum herum ist erst einmal nebensächlich sondern eher die vorgehensweise beim empfang.
Könnte ein ambitioniertes Midglied des Forums einmal drüber schaun und mir evtl unter die arme greifen. Auch habe ich das gefühl das ich die ansteuerung des Moduls noch nicht so ganz verstanden habe.



CodeBox Assembler
;;;Kleines Testprogramm
;;Tiny2313 als empfänger
;;Empfängt ein Byte und gibt dieses via usart aus
;;USI als SPI Master
;;interruptausgang von RFM an INT0
;;SPI standartverdrahtung
;;
.list
.include "tn2313def.inc"

.nolist
.equ XTAL=1000000
.equ t5ms = ( XTAL * 5 / 606 ) / 1000

.def temp1=r16
.def temp2=r17
.def temp3=r18
.def data=r19
.def lsb=r21
.def msb=r22
.def datain=r23
.org 0x0000
.equ spiddr=ddrb
.equ spiport=portb
.equ nsel=0
.def counter=r20
rjmp start
.org 0x0001
   rjmp Ext0_int_handle
.org 0x0006
   rjmp Timer0OFL

.org 0x020
loop:
mov data, lsb
sleep
cp data, lsb
breq loop
mov temp1, lsb
rcall seroutdez
rjmp loop



start:
ldi temp1, low(ramend)
out spl, temp1                           ;Stackpointer init
sbi spiddr, nsel
rcall rfninit                           ;RFM12 inittialisiert und bereit("hoffentlich")
rcall initrs232
rcall int0_init
rcall inittimer0
sei
rcall loop






;**********************************************
;UNTERPROGRAMME
;**********************************************
send_byte:
push lsb
;sender einschalten
ldi msb, 0x82
ldi lsb, 0x20
rcall send_command
;DATENBIT MUSS IN LSB Stehen
ldi msb, 0xB8
push lsb
ldi lsb, 0xAA               ;präambel
rcall send_command
rcall send_command
;;nun das synchronbyte
ldi lsb, 0x2D
rcall send_command
ldi lsb, 0xD4
rcall send_command
;;nun die nutzdaten
pop lsb
rcall send_command
;Zeit geben
rcall delay100ms
;sender wider ausschalten und empfänger an
ldi msb, 0x82
ldi lsb, 0x80
rcall send_command

ret

read_byte:
;;DATENBYTE befindet sich in LSB
ldi msb, 0xB0
ldi lsb, 0x00
rcall send_command
in lsb, USIDR
ret

send_command:
mov temp1, msb
cbi spiport,nsel
rcall SPITransfer
mov temp1, lsb
rcall SPITransfer
sbi spiport,nsel

ret




SPITransfer:
out    USIDR,temp1
ldi    r16,(1<<USIOIF)
out    USISR,r16
ldi    r17,(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)

SPITransfer_loop:
out    USICR,r17
in     r16, USISR
sbrs   r16, USIOIF
rjmp   SPITransfer_loop
in     temp1,USIDR
ret

ret
;******************************************************************
;RS232 Routine
;******************************************************************
initrs232:
.equ takt = 1000000 ; 16/8 MHz Systemtakt
.equ baud =2400   ; Baudrate
.equ ubrr_val = ((takt+baud*8)/(baud*16)-1)   ; clever Runden
.equ baud_real = (takt/(16*(ubrr_val+1)))   ; tatsächliche Baudrate
.equ baud_error = ((baud_real*1000)/baud-1000)   ; Fahler in Promille
;
;
.if ((baud_error> 10) || (baud_error <-10))       ; max +/- 10 Promill Fehler
   .error "Systematischer Fehler der Baudrate größer als 1 Prozent und damit zu hoch!"
.else
   .message "Systematischer Fehler der Baudrate hält sich in Grenzen - OK!"
.endif
rcall serinit
rcall hallo
ret

seroutdez:
           push  temp1            ; die Funktion verändert temp1 und temp2,
           push  temp2            ; also sichern wir den Inhalt, um ihn am Ende
                                  ; wieder herstellen zu können

           mov   temp2, temp1     ; das Register temp1 frei machen
                                  ; abzählen wieviele Hunderter
                                  ; in der Zahl enthalten sind
;** Hunderter **
           ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen
number_1:
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
                                  ; Durchlauf eine '0' in temp1)
           subi  temp2, 100       ; 100 abziehen
           brcc  number_1     ; ist dadurch kein Unterlauf entstanden?
                                  ; nein, dann zurück zu lcd_number_1
           subi  temp2, -100      ; 100 wieder dazuzählen, da die
                                  ; vorherhgehende Schleife 100 zuviel
                                  ; abgezogen hat
           cpi temp1, 0           ;Führende null weg
           breq number_2
           rcall serout        ; die Hunderterstelle ausgeben

;** Zehner  **
           ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen
number_2:
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
                                  ; Durchlauf eine '0' in temp1)
           subi  temp2, 10        ; 10 abziehen
           brcc  number_2     ; ist dadurch kein Unterlauf enstanden?
                                  ; nein, dann zurück zu lcd_number_2
           subi  temp2, -10       ; 10 wieder dazuzählen, da die
                                  ; vorherhgehende Schleife 10 zuviel
                                  ; abgezogen hat
           cpi temp1, 0           ;Führende null weg
           breq number_3
           rcall serout        ; die Zehnerstelle ausgeben
;** Einer **       
number_3:
           ldi   temp1, '0'       ; die Zahl in temp2 ist jetzt im Bereich
           add   temp1, temp2     ; 0 bis 9. Einfach nur den ASCII Code für
           rcall serout         ; '0' dazu addieren und wir erhalten dierekt
                                  ; den ASCII Code für die Ziffer


           pop   temp2            ; den gesicherten Inhalt von temp2 und temp1
           pop   temp1            ; wieder herstellen
           ret                    ; und zurück





hallo:
ldi temp1, 'O'
rcall serout
ldi temp1, 'K'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, 'R'
rcall serout
ldi temp1, 'S'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, '2'
rcall serout
ldi temp1, '3'
rcall serout
ldi temp1, '2'
rcall serout
ret

serout:
   sbis ucsra,udre                   ; udre-bit ist gesetzt, wenn der Sendepuffer leer ist
                                   ; UART Data Register Empty
   rjmp serout
   out    udr, temp1                   ; Zeichen senden
   ret                               ; zurück aus der Subroutine

   ; Zeichen über RS232 einlesen
   ; temp1: gibt das Zeichen zurück
serin:
   sbis ucsra, rxc   
   rjmp serin                       ; wir warten bis ein Byte angekommen ist

   in temp1, udr                   ; Zeichen einlesen
   ;rcall serout                   ; und zurücksenden   
   ret

   ; Zeichen über RS232 einlesen und als Echo zurücksenden
   ; temp1: gibt das Zeichen zurück


serinit:
   ; Baudrate für RS232 einstellen
   ldi temp1, high(ubrr_val)       ; zuerst Baudrate Highbyte (davon Lownibble)
   out ubrrh, temp1
   ldi temp1, low(ubrr_val)           ; Lowbyte schreiben und prescaler damit triggern
   out ubrrl, temp1

   ; frameformat setzen
   ldi temp1, (1<<ucsz1) | (1<<ucsz0)   ; ucsz2:0 = 0 1 1 -> 8 Bit Daten, kein Parity, 1 Stopbit
   out ucsrc, temp1

   ; Transmitter einschalten, PortD Bit1 wird überschrieben
   sbi ucsrb, txen                   ; TXE-Bit (3) setzen
   
   ; Receiver einschalten, PortD Bit0 wird überschrieben
   sbi ucsrb, rxen                   ; RXE-Bit (4) setzen
   ;sbi ucsrb, rxcie               ; RXCIE-bit (7) setzen, damit ein irq ausgelöst werden kann, wenn ein Zeichen da ist
   ret



;***********************************************************
;INITS
;***********************************************************
;;Nsel auf low einen momment warten dann bit an SDI vom modul(mit dem höchsten bit starten)
; high low an sclk(serial clock) nächstes bit.....dann Nsel wieder auf high
rfninit:
;folgende init werte zum übertragen
;Empfänger:
;0x80E7       868mhz, RX fifo TX buffer 12pf
;0x8280       enable receiver
;0xA640       868mhz center freq
;0xC647       19,2kbaud
;0x9582       Max empfangsstärke 200khz pin als VDI pin
;0xC2AC       digitaler fehlerbehebung
;0xCA81       
;0xC483
;0x9850       TX controll
;0xE000
;0xC800
;0xC040
;KOmmando  0xB000 read 8 bits from fifoRX
;kommando 0xB8xx   send 8 bits of data
ldi msb, 0x80
ldi lsb, 0xE7
rcall send_command

ldi msb, 0x82
ldi lsb, 0x80
rcall send_command

ldi msb, 0xA6
ldi lsb, 0x40
rcall send_command

ldi msb, 0xC6
ldi lsb, 0x47
rcall send_command

ldi msb, 0x95
ldi lsb, 0x82
rcall send_command

ldi msb, 0xc2
ldi lsb, 0xAC
rcall send_command

ldi msb, 0xCA
ldi lsb, 0x81
rcall send_command

ldi msb, 0xc4
ldi lsb, 0x83
rcall send_command

ldi msb, 0x98
ldi lsb, 0x50
rcall send_command

ldi msb, 0xE0
ldi lsb, 0x00
rcall send_command

ldi msb, 0xC8
ldi lsb, 0x00
rcall send_command

ldi msb, 0xC0
ldi lsb, 0x40
rcall send_command

ret


usi_init:
;;USIWM1 und 0 für SPI

;; 0       1
ret

int0_init:
        ldi temp1,(1<<ISC01)|(0<<ISC00)
        out mcucr,temp1
        ldi temp1, (1<<INT0)
        out GIMSK,temp1
        ret

inittimer0:
       sbr temp1, TOIE0
       out TIMSK, temp1
       ldi temp1,0b00000111   ;max prescaler...bei 1mhz 255*1024=262144 takte
                               ; was bei 1 mhz 1/4sek ist
       out TCCR0B, temp1
       ret
;****************************************************************
;INTERRUPTHANDLERS
;****************************************************************
Ext0_int_handle:
;;Daten stehen bereit
;;Auslesen
rcall read_byte
reti

Timer0OFL:
inc counter
cpi counter, 229
brne schlafen
cpi counter, 229
breq wach
reti

schlafen:
sleep
ret
wach:
clr counter
ret

.include "stddelay.inc"


Dies ist die software des empfängers

Und das die des Senders



CodeBox Assembler

.include "tn44def.inc"
.def temp1=r16
.def temp2=r17
.def temp3=r18
.def datain=r19
.equ spiport=porta
.equ spiddr=ddra
.def lsb= r20
.def msb=r21
.equ XTAL=1000000
.equ t5ms = ( XTAL * 5 / 606 ) / 1000
.equ nsel=3

loop:
inc r22
mov lsb, r22
rcall send_byte
rcall delay1s
rjmp loop

start:
ldi temp1, high(ramend)
out sph, temp1
ldi temp1, low(ramend)
out spl, temp1                           ;Stackpointer init
sbi spiddr, nsel
rcall rfninit                           ;RFM12 inittialisiert und bereit("hoffentlich")
rcall loop
;;;;;;;;;;;;;;;;;;;;;UNTERPROGRAMME


rfninit:
;folgende init werte zum übertragen
;Empfänger:
;0x80E7       868mhz, RX fifo TX buffer 12pf
;0x8280       enable receiver
;0xA640       868mhz center freq
;0xC647       19,2kbaud
;0x9582       Max empfangsstärke 200khz pin als VDI pin
;0xC2AC       digitaler fehlerbehebung
;0xCA81       
;0xC483
;0x9850       TX controll
;0xE000
;0xC800
;0xC040
;KOmmando  0xB000 read 8 bits from fifoRX
;kommando 0xB8xx   send 8 bits of data
ldi msb, 0x80
ldi lsb, 0xE7
rcall send_command

ldi msb, 0x82
ldi lsb, 0x80
rcall send_command

ldi msb, 0xA6
ldi lsb, 0x40
rcall send_command

ldi msb, 0xC6
ldi lsb, 0x47
rcall send_command

ldi msb, 0x95
ldi lsb, 0x82
rcall send_command

ldi msb, 0xc2
ldi lsb, 0xAC
rcall send_command

ldi msb, 0xCA
ldi lsb, 0x81
rcall send_command

ldi msb, 0xc4
ldi lsb, 0x83
rcall send_command

ldi msb, 0x98
ldi lsb, 0x50
rcall send_command

ldi msb, 0xE0
ldi lsb, 0x00
rcall send_command

ldi msb, 0xC8
ldi lsb, 0x00
rcall send_command

ldi msb, 0xC0
ldi lsb, 0x40
rcall send_command

ret


send_byte:
push lsb
;sender einschalten
ldi msb, 0x82
ldi lsb, 0x20
rcall send_command
;DATENBIT MUSS IN LSB Stehen
ldi msb, 0xB8
push lsb
ldi lsb, 0xAA               ;präambel
rcall send_command
rcall send_command
;;nun das synchronbyte
ldi lsb, 0x2D
rcall send_command
ldi lsb, 0xD4
rcall send_command
;;nun die nutzdaten
pop lsb
rcall send_command
;Zeit geben
rcall delay100ms
;sender wider ausschalten und empfänger an
ldi msb, 0x82
ldi lsb, 0x80
rcall send_command

ret

read_byte:
;;DATENBYTE befindet sich in LSB
ldi msb, 0xB0
ldi lsb, 0x00
rcall send_command
in lsb, USIDR
ret

send_command:
mov temp1, msb
cbi spiport,nsel
rcall SPITransfer
mov temp1, lsb
rcall SPITransfer
sbi spiport,nsel

ret




SPITransfer:
out    USIDR,temp1
ldi    r16,(1<<USIOIF)
out    USISR,r16
ldi    r17,(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)

SPITransfer_loop:
out    USICR,r17
in     r16, USISR
sbrs   r16, USIOIF
rjmp   SPITransfer_loop
in     temp1,USIDR
ret

.include "stddelay.inc"



Leider funktioniert nichts. das Empfängermodul zeigt mir via USART nicht mal das "hallo" an..

Desweiteren gibt es einige offene Fragen die mich quälen:


-wenn ich 8 bits per SPI an das RFM übertrage mit vorhergehendem msb 0x82
werden diese 8 bits dann sofort vom modul übertragen?

-kann ich diese 8 bits beim empfänger mit dem senden von 0xB000 direkt auslesen und sie aus dem USIDR entnehmen?

-kann ich das Modul einmal konfigurieren und dann durchgehend warten lassen bis etwas kommt, oder fängt es dann nur müll ein?

-wie ist das mit dem VDI pin bzw nINT. Muss ich diese nutzen? oder kann ich auch softwareseitig sicher stellen wann neue daten vorhanden sein müssten.

-Wenn ich den FIFO lese während das MOdul etwas empfängt, bekomme ich dann bitsalat oder bleiben die daten im FIFO so lange bestehen bis alle 8 bits empfangen sind und werden dann in den FIFO verschoben.

Ich möchte möglichst mit einer minimalen beschaltung auskommen. Das nutzen eines externen intterupts wäre evtl noch eine nette sache. z.B intterupt wenn daten empfangen wurden...Dann auslesen und den MC in den sleep mode

Ich hoffe ihr könnt mir helfen. Ich stecke nämlich fest...
 
Hallo und willkommen im Forum!

Ich kann dir selber kurzfristig leider nicht helfen, da ich mich erst in das Datenblatt des RFM12 reinlesen müsste. Dafür fehlt mir im Moment die Zeit, vielleicht komme ich am Wochenende dazu.

Bitte weise doch die User das nächste mal darauf hin, dass du ein Crossposting erstellt hast, bitte auch im anderen Forum. So bekommen User eher mit, wenn es Lösungsansätze oder Lösungen gibt und das spart einiges an Zeit und Mühe. :)

Dirk :ciao:
 
Hallo Dirk. Danke für deine schnelle Antwort. Ja es ist ein Crossposting vom Roboternetz, dar sich dort leider kaum mehr jemand mit Assembler beschäftigt. Danke das du versuchst mir weiter zu helfen. Leider fühl ich mich manchmal etwas missverstanden... ich hoffe du verstehst meinen Code ausreichend...Meine Programmierkünste scheinen mir mehr als schlecht. Ich habe damals in der Schulzeit einen 1 jährigen kurs besucht(10sitzungen) wo die thematik angekratzt wurde..Leider sehe ich keinen Fortschritt in meiner Programmiertechnik...Back to Topic. Das Datenblatt könnte was die befhle angeht etwas irreführend sein. Ich selbst habe 3 verschiedene Datenblätter hier rumliegen...Immer wieder wird ein Befehl mit einem anderen Hex wert angegeben.

Bei meiner software:

Die USART schnittstelle muss funktionieren(habe die initialisierung mit einer "hallo"-loop geflasht)==> alles :good3:
Ob ich das USI richtig verstanden habe bezweifle ich bis jetzt noch stark.
Nun bin ich mit der ganzen Situation (auch zwecks gegebenen Zeitmangels) etwas überfordert. Um so mehr ich über das RFM12 Modul lese um so größer wird die verwirrung.
Der erste 2313 ist bereits den 100000000 x Flashen zu opfer gefallen :(

Ich wäre auch sehr dankbar über anregungen, was man in den Programmen anders lösen könnte.

mfg Daniel
 
Hallo Daniel,

es gibt hier einige User die Assembler programmieren, ich komme damit auch klar :). Mein Problem ist im Moment nur, mich mit dem RFM12 genauer auseinanderzusetzen, Problem ist die wenige Zeit. Inzwischen verwendet man eher fertige Bibliotheken (Arduino, Bascom ...), da muss man sich nicht mit der Low-Level-Thematik rumschlagen.

Eventuell kann dir ja schon ein anderer User helfen (@LotadaC kennt sich schon mal in Assembler und der tinyAVR Hardware sehr gut aus, vielleicht findet er an deinem Code schon etwas unabhängig vom RFM12). Ansonsten schaue ich mir das auch am Wochenende mal an.

Dirk :ciao:
 
  • Like
Reaktionen: dannyboy1994
Ich habe scho einige Beiträge von @LotadaC und @dino03 und dir dirk gelesen und muss gerade wirklich einmal erwähnen, das ihr wirkliche spezialisten auf dem Gebiet AVR Programmierung seid. Ach wäre es schön wenn das Projekt vom breadboard in die Ätzanlage wandern kann.
Ich habe mit verschiedenen Parametern des RFM etwas herum "gespielt" bin aber leider nicht weiter gekommen.

Hier einmal die beschaltung der controller.
nicht das hier der Fehler verborgen liegt und ich einfach zu blind dafür bin.:hmmmm:
tiny2313:
nIRQ = pin6
nsel= Pin12
sck = pin19
sdi = pin18
sdo = pin17

tiny44:
nIRQ = pin 10
nsel = pin3
sck = pin9
sdi = pin8
sdo = pin7


beide laufen auf 8Mhz mit aktiver ckdiv8 fuse also 1 MHZ
Beide werden durch eine CR24xx Knopfzelle 3V gespeist
sonstige hardware beschränckt sich auf das mindeste. Reset Pullup beim tiny2313 Quarzbeschaltung(zwecks USART) und jeweils einer lox current LED als("POWERLED"), und einem 100nF kondensator zwischen vcc und gnd pin des controllers. Spannung passt auch beide batterien sind frisch. Ich denke um so mehr Infos ich liefern kann um so leichter wird das finden des Problems. Ich bedanke mich schon einmal für jeden Hilfreichen Tipp.:bath:

Daniel
 
Das ist ja schon fast 'ne Herrausforderung, Dirk...

Also ich kann nichts versprechen, aber wenn ich Zeit finde schau ich mir das Datenblatt und den Code mal an.
dankbar über anregungen, was man in den Programmen anders lösen könnte
Auf den ersten Blick fallen ein paar, eher kosmetische Kleinigkeiten auf...
  • In den Interruptvektortabellen verwendest Du die .org-Direktiven mit festen Zahlenwerten - diese Werte sind in den vorher inkludierten Prozessordefinitionsdateien mit Namen versehen worden - kannst also die Namen verwenden (das ändert natürlich am Programm nichts, aber ist übersichtlicher - genau dafür sind die da definiert)
  • Ich sehe keinen Grund, warum Du den Initialisierungsblock (start-label) im Flash hinter die Hauptprogrammschleife gesetzt hast. Grundsätzlich ist das natürlich egal, aber andersrum entfällt der Sprung vom Init-Block zum Hauptprogramm (loop-label). In dem Zusammenhang-->
  • Diesen Sprung hast Du in beiden Programmen als relative call ausgeführt, das heißt es wird die derzeitige Flashadresse auf den Stack gepusht und dann gesprungen. Zu diesem call gibt es kein Return, die Adresse wird nie wieder vom Stack genommen. Sowas ist ein Kandidat für üble Stacküberläufe - hier allerdings nicht, da Du den Start-Block nie wieder erreichst. Du hast halt nur unnütze zwei Bytes auf den Stack gepackt.
  • Beim Reset werden in jedem AVR die (meisten) I/O-Register initialisiert - insbesondere auch der Stackpointer. Die konkreten initial values stehen dazu in den Controller-Datenblättern. Bei Deinen beiden Controllern ist das für den Stackpointer bereits RAMEND, eine nochmalige Initialisierung kannst(!) Du Dir also sparen.
  • Du hast in der rfninit schön die ganzen word-Werte dokumentiert, und die dann ja zu Fuß mit LDI geladen. Ich würde die stattdessen irgendwo als Compilerkonstante definieren (.equ, mit 'nem geeigneten Kommentar natürlich), und dann so verfahren, wie Du das bereits mit dem Stackpointer hast.
Da das alles Words zu sein scheinen, könnte man die aber auch alle im Flash ablegen (.DW), und dann mit LPM laden. Die tatsächlichen Adressen im Flash wählt man dabei (mit .org) geschickt so, daß alle Adressen dasselbe Highbyte haben.
Für "enable reciever" hättest Du also dann

CodeBox Assembler
.org [Flashadresse]
enable_reciever:
.DW 0x8280

Um das zu senden ist also der Label in die Z-Register zu laden, wobei das Highbyte ja geschickt festgelegt sein sollte - entsprechend müßte nur noch das Low-Register festgelegt werden


CodeBox Assembler
LDI ZL, low(enable_reciever)

Ein SPM mit post increment lädt das erste Byte in ein Register (bereit für das USI), außerdem zeigt Z auf das zweite Byte. Ein weiteres SPM das zweite.
Das Laden des Z-Pointers und der Aufruf der eigentlichen Senderoutine (mit den SPMs) kann man dann elegant als Macro gestalten, welches dann nur noch mit "sendcommand enable_reciever" o.ä. aufgerufen werden muß...

Auf UART, USI und den externen IC bin ich jetzt noch nicht eingegangen - nur noch ein Hinweis: bei einigen Tinies existiert ein Buffer-Register, über das der Lesezugriff erfolgen kann (gepuffert).
Leider sind die Datenblätter diesbezüglich teilweise inkorrekt/wiedersprüchlich.
Ich habe in meiner Tiny-Übersicht vermerkt, welche Tinies einen gepufferten USI besitzen (zB der Tiny2313A), und welche nicht (zB der Tiny2313).
(Hatte mich dazu an den Atmel-Support gewendet - aber natürlich garantiere ich keine Korrektheit der Angaben)
 
Guten Abend Lotada.

In den Interruptvektortabellen verwendest Du die .org-Direktiven mit festen Zahlenwerten - diese Werte sind in den vorher inkludierten Prozessordefinitionsdateien mit Namen versehen worden - kannst also die Namen verwenden (das ändert natürlich am Programm nichts, aber ist übersichtlicher - genau dafür sind die da definiert)
Das war mir bis jetzt leider nicht bekannt. Ich werde mir die inc mal etwas näher ansehen. Das würde das ganze erheblich vereinfachen.

Das sich der Startblock hinter dem Loop Block befindet ist eine sehr gute Frage :D ich tippe auf reinen zufall. Ich musst den ganzen Code etwas sortieren. wollte euch ja nicht mein vollkommenes chaos unterjubeln. Das hab ich wohl etwas vertauscht... der rcall sollte natürlich ein rjmp sein... mich beunruhigt auch das ich dort das ret vergessen habe, also in dem startblock. sollte aus irgendeinem grund zurück gesprungen werden, durch einen dummen programmierfehler, würde sich das ganze vollständig verselbstständigen ...
Den Stack zu initialisieren ist eine angewohnheit. Aber gut zu wissen das dies eigentlich unnötig ist. Ich nutze eigentlich nur tiny2313 m8 m328p m32 tiny85 tiny13 und den neu ins bott gekommen tiny44. Hast du eine ungefähre Seitenzahl wo die initwerte des controllers im datenblatt zu finden sind?

Das zufuß senden hat sich ergeben durch das oftmaliege ändern und den versuch jede fehlerquelle zu eliminieren.....erfolglos.
Der Z-Pointer war für mich schon immer interessant, aber aus irgend einem grund kann ich mir das einfach nicht merken und meide daher das ablegen von Daten im Flash.

Danke für diese Tipps. Ich werde es morgen gleich nocheinmal etwas überarbeiten. Für heute ist es spät genug. Vielen Danke

 
...Ich werde mir die inc mal etwas näher ansehen. Das würde das ganze erheblich vereinfachen...
Im Prinzip ist das nur 'ne "Tabelle", die diverse (mehr oder weniger nützliche) .equ-Konstanten definiert. Welche Entwicklungsumgebung nutzt Du eigentlich? Beim aktuellen ATMEL-Studio gibt man ja eigentlich die zu inkludierende Definitionsdatei nicht mehr an (man muß den verwendeten Controller auswählen, die inklusion erfolgt automatisch, was man aber im Code dann nicht sieht (also schlecht für Codeschnipsel - ich packe das dann zumindest als Kommentar mit rein))
...Das sich der Startblock hinter dem Loop Block befindet ist eine sehr gute Frage :D ich tippe auf reinen zufall...
Letztlich isses Wurscht... Du programmierst Assembler - der Controller macht jeden Quatsch den Du ihm anweist. Dummerweise muß das nicht unbedingt das sein, was Du willst;)
...Den Stack zu initialisieren ist eine angewohnheit. Aber gut zu wissen das dies eigentlich unnötig ist...
Meiner Meinung nach werden bei allen AVR beim Reset alle (ok, nur beschreibbare Bits, klar)) I/Os initialisiert. Früher war das dann überall 0x00. Bei moderneren (ist auch schon 'ne weile her) Controllern sinds teilweise nützlichere Werte, beim Stackpointer eben RAMEND. Reinitialisieren schadet ja nicht (abgesehen von Flash- und Zeitverbrauch)...
...Hast du eine ungefähre Seitenzahl wo die initwerte des controllers im datenblatt zu finden sind?...
Die sind über das ganze DB verstreut (nämlich immer bei der Beschreibung der dazugehörenden Hardware-Komponente) - aber üblicherweise als eines der letzten Kapitel in den Datenblättern findest Du das Register Summary, und da ist die Seitenzahl angegeben (auch als link), wo das Register behandelt wird, und dort wiederum findest Du auch die initial values dieses Registers.
Bei neueren Controllern (bzw häufig genutzten, bei denen das Datenblatt "aufgehübscht" wurde) wird statt "initial value" "reset" verwendet.
...Der Z-Pointer war für mich schon immer interessant, aber aus irgend einem grund kann ich mir das einfach nicht merken und meide daher das ablegen von Daten im Flash...
Nachvollziehbar, aber gerade beim Init des Funkmoduls überträgst Du nacheinander viele words. Die lange derzeitige Form ist im Code doch recht unübersichtlich - im Flash könntest Du eben alles als Block ablegen, und an einer Stelle Änderungen vornehmen. Du kannst zB auch alle Init-Words in eine .dw-Zeile schreiben...

P.S.: Willkommen hier, auch von mir.
LotadaC
 
Ich benutze AVR studio 4.19... Ich wollte schon mal auf studio 6 umsteigen, aber dar ich meine programme auf nem USB stick welcher am router steckt speichere und hauptsächlich auf einem AMD Athlon 2600 mit 1,5GB RAM programmiere welcher an meinem "Basteltisch" auf dem Spitzboden steht war ich mir nicht so ganz schlüssig. Auf meinem notebook läuft es natürlich problemlos, doch wollte ich mir nicht die mühe machen den Athlon zu quälen um herrauszufinden das es nicht richtig funktioniert.
Zum Programmieren nutze ich ein USB ASP oder einen selbstgebauten rs232 Programmer via myAVRprogtool, wobei mir der serielle lieber ist, dar schneller.
desweiteren bin ich "nichtstolzer" besitzer eines ardoinos..mit mega 328P. Den hab ich mir damals bestellt aus der überlegung herraus AVR ist AVR und so steckt er auf einem kompakten board. Leider werden beim arduino so viele pins vergoidet, das er bis jetzt keinen sinnvollen nutzen erbracht hat...32kb Flash... reine verschwendung den prozi für irgendeine kleine LCD anwendung oder ähnliches zu nutzen. Programmieren tu ich eigentlich Ausschließlich in Asm. C war mir leider schon immer zu klammerig. Außerdem liebe ich es zu wissen was ich gerade tu, welche register ich wann wie beschreibe, jedes kleine detail...was das Programmieren in C oder Bascom für mich so unsympatisch macht.
I

Nachvollziehbar, aber gerade beim Init des Funkmoduls überträgst Du nacheinander viele words. Die lange derzeitige Form ist im Code doch recht unübersichtlich - im Flash könntest Du eben alles als Block ablegen, und an einer Stelle Änderungen vornehmen. Du kannst zB auch alle Init-Words in eine .dw-Zeile schreiben...

Es gab ja auch etwas ala postincrement oder predecrement oder wie das ganze bezeichnet wird. Das wäre natürlich eine unbeschreiblich aufwandsminderung wenn man lle werte die man z.B in diesem Fall für das RFM benötigt" einfach" nacheinander aus dem Flash läd und via SPI sendet. Das ganze werde ich mir jetzt auf jeden Fall auch noch einmal versuchen zu verinnerlichen. Den aktuellen Code werde ich später noch einmal posten. An der Funktion hat sich nichts geändert==> es funktioniert nichts
 
Hallo zusammen,

ich habe mir den Sourcecode angeschaut und ich denke ich habe einen Fehler gefunden ...
(SPI und RFM12B Initialsierung und Senden/Empfangen habe ich mir noch nicht näher angesehen)


Sender:

Bei der Routine send_byte sicherst du lsb zweimal auf dem Stack (push) aber holst lsb nur einmal wieder vom Stack (pop).
Der Stackpointer zeigt dann für das ret nicht mehr auf die richtige Rücksprungadresse. Das Programm "stürzt" sofort ab.

Einmal würde gesendet, direkt nach der Initialisierung.

---

Noch ein paar Hinweise oder Tipps:

Bei send_command würde ich zum Testen nach
cbi spiport,nsel
einige nop einfügen.

Allgemein würde ich nach Reset, also beim Start vor der Initialisierung von externer Peripherie eine kleine Pause einfügen, damit sich die Betriebsspannung für andere Komponenten ausreichend stabilisiert hat und diese auch selber bereit sind, Kommandos zu verarbeiten (also hier der RFM12B).

Dirk :ciao:
 
Ich habe nun einmal eure Tipps angewendet. Ich wäre dankbar wenn @LotadaC sich den bereich mit dem Z pointer etwas genauer ansehen könnte


CodeBox Assembler
;;;Kleines Testprogramm
;;Tiny2313 als empfänger
;;Empfängt ein Byte und gibt dieses via usart aus
;;USI als SPI Master
;;interruptausgang von RFM an INT0
;;SPI standartverdrahtung
;;
.list
.include "tn2313def.inc"

nach erneutem flashen erhalte ich nur leider immer noch keine ausgabe im terminal. Auch habe ich mir das datenblatt nocheinmal angesehen und gluabe mitlerweile das auch mit der verwendung des nirq pins etwas nicht richtig ist. Die Funktion der Pins ist leider nirgens 100% genau beschriben. Und ich muss eingestehen das ich auch noch so blöd war und die smd module mit 2mm raster hier habe..Das heisst es ist mit ca 10cm langen drähten eines Y(st)y verkabelt. Wobei das ja bei SPI kein problem darstellen sollte.
.nolist
.equ XTAL=1000000
.equ t5ms = ( XTAL * 5 / 606 ) / 1000

.def temp1=r16
.def temp2=r17
.def temp3=r18
.def data=r19
.def lsb=r21
.def msb=r22
.def datain=r23
.org 0x0000
.equ spiddr=ddrb
.equ spiport=portb
.equ nsel=0
.def counter=r20
rjmp start
.org 0x0001
   rjmp Ext0_int_handle
.org 0x0006
   rjmp Timer0OFL

.org 0x020




start:
ldi temp1, low(ramend)
out spl, temp1                           ;Stackpointer init
sbi spiddr, nsel
                           ;RFM12 inittialisiert und bereit("hoffentlich")
rcall delay100ms           ; nach dirk kleines delay um den externen geräten zeit zu geben
rcall initrs232
rcall hallo
rcall int0_init
rcall rfninit
;rcall inittimer0
sei
rcall loop


loop:
rcall hallo
mov data, lsb
;sleep
rcall read_byte
cp data, lsb
breq loop
mov temp1, lsb
rcall seroutdez
rjmp loop



;**********************************************
;UNTERPROGRAMME
;**********************************************
send_byte:
push lsb
;sender einschalten
ldi msb, 0x82
ldi lsb, 0x20
rcall send_command
;DATENBIT MUSS IN LSB Stehen
ldi msb, 0xB8
push lsb
ldi lsb, 0xAA               ;präambel
rcall send_command
rcall send_command
;;nun das synchronbyte
ldi lsb, 0x2D
rcall send_command
ldi lsb, 0xD4
rcall send_command
;;nun die nutzdaten
pop lsb
rcall send_command
;Zeit geben
rcall delay100ms
;sender wider ausschalten und empfänger an
ldi msb, 0x82
ldi lsb, 0x80
pop lsb                       ;16.12.2016
rcall send_command

ret

read_byte:
;;DATENBYTE befindet sich in LSB
ldi msb, 0xB0
ldi lsb, 0x00
rcall send_command
in lsb, USIDR
ret

send_command:
mov temp1, msb
cbi spiport,nsel
nop nop nop nop           ;Zu testzwecken nach Dirk ein kleines delay
nop nop nop nop
rcall SPITransfer
mov temp1, lsb
rcall SPITransfer
sbi spiport,nsel

ret




SPITransfer:
out    USIDR,temp1
ldi    r16,(1<<USIOIF)
out    USISR,r16
ldi    r17,(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)

SPITransfer_loop:
out    USICR,r17
in     r16, USISR
sbrs   r16, USIOIF
rjmp   SPITransfer_loop
in     temp1,USIDR
ret

ret
;******************************************************************
;RS232 Routine
;******************************************************************
initrs232:
.equ takt = 1000000 ; 16/8 MHz Systemtakt
.equ baud =2400   ; Baudrate
.equ ubrr_val = ((takt+baud*8)/(baud*16)-1)   ; clever Runden
.equ baud_real = (takt/(16*(ubrr_val+1)))   ; tatsächliche Baudrate
.equ baud_error = ((baud_real*1000)/baud-1000)   ; Fahler in Promille
;
;
.if ((baud_error> 10) || (baud_error <-10))       ; max +/- 10 Promill Fehler
   .error "Systematischer Fehler der Baudrate größer als 1 Prozent und damit zu hoch!"
.else
   .message "Systematischer Fehler der Baudrate hält sich in Grenzen - OK!"
.endif
rcall serinit
rcall hallo
ret

seroutdez:
           push  temp1            ; die Funktion verändert temp1 und temp2,
           push  temp2            ; also sichern wir den Inhalt, um ihn am Ende
                                  ; wieder herstellen zu können

           mov   temp2, temp1     ; das Register temp1 frei machen
                                  ; abzählen wieviele Hunderter
                                  ; in der Zahl enthalten sind
;** Hunderter **
           ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen
number_1:
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
                                  ; Durchlauf eine '0' in temp1)
           subi  temp2, 100       ; 100 abziehen
           brcc  number_1     ; ist dadurch kein Unterlauf entstanden?
                                  ; nein, dann zurück zu lcd_number_1
           subi  temp2, -100      ; 100 wieder dazuzählen, da die
                                  ; vorherhgehende Schleife 100 zuviel
                                  ; abgezogen hat
           cpi temp1, 0           ;Führende null weg
           breq number_2
           rcall serout        ; die Hunderterstelle ausgeben

;** Zehner  **
           ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen
number_2:
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
                                  ; Durchlauf eine '0' in temp1)
           subi  temp2, 10        ; 10 abziehen
           brcc  number_2     ; ist dadurch kein Unterlauf enstanden?
                                  ; nein, dann zurück zu lcd_number_2
           subi  temp2, -10       ; 10 wieder dazuzählen, da die
                                  ; vorherhgehende Schleife 10 zuviel
                                  ; abgezogen hat
           cpi temp1, 0           ;Führende null weg
           breq number_3
           rcall serout        ; die Zehnerstelle ausgeben
;** Einer **    
number_3:
           ldi   temp1, '0'       ; die Zahl in temp2 ist jetzt im Bereich
           add   temp1, temp2     ; 0 bis 9. Einfach nur den ASCII Code für
           rcall serout         ; '0' dazu addieren und wir erhalten dierekt
                                  ; den ASCII Code für die Ziffer


           pop   temp2            ; den gesicherten Inhalt von temp2 und temp1
           pop   temp1            ; wieder herstellen
           ret                    ; und zurück





hallo:
ldi temp1, 'O'
rcall serout
ldi temp1, 'K'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, 'R'
rcall serout
ldi temp1, 'S'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, '2'
rcall serout
ldi temp1, '3'
rcall serout
ldi temp1, '2'
rcall serout
ret

serout:
   sbis ucsra,udre                   ; udre-bit ist gesetzt, wenn der Sendepuffer leer ist
                                   ; UART Data Register Empty
   rjmp serout
   out    udr, temp1                   ; Zeichen senden
   ret                               ; zurück aus der Subroutine

   ; Zeichen über RS232 einlesen
   ; temp1: gibt das Zeichen zurück
serin:
   sbis ucsra, rxc
   rjmp serin                       ; wir warten bis ein Byte angekommen ist

   in temp1, udr                   ; Zeichen einlesen
   ;rcall serout                   ; und zurücksenden
   ret

   ; Zeichen über RS232 einlesen und als Echo zurücksenden
   ; temp1: gibt das Zeichen zurück


serinit:
   ; Baudrate für RS232 einstellen
   ldi temp1, high(ubrr_val)       ; zuerst Baudrate Highbyte (davon Lownibble)
   out ubrrh, temp1
   ldi temp1, low(ubrr_val)           ; Lowbyte schreiben und prescaler damit triggern
   out ubrrl, temp1

   ; frameformat setzen
   ldi temp1, (1<<ucsz1) | (1<<ucsz0)   ; ucsz2:0 = 0 1 1 -> 8 Bit Daten, kein Parity, 1 Stopbit
   out ucsrc, temp1

   ; Transmitter einschalten, PortD Bit1 wird überschrieben
   sbi ucsrb, txen                   ; TXE-Bit (3) setzen
 
   ; Receiver einschalten, PortD Bit0 wird überschrieben
   sbi ucsrb, rxen                   ; RXE-Bit (4) setzen
   ;sbi ucsrb, rxcie               ; RXCIE-bit (7) setzen, damit ein irq ausgelöst werden kann, wenn ein Zeichen da ist
   ret



;***********************************************************
;INITS
;***********************************************************
;;Nsel auf low einen momment warten dann bit an SDI vom modul(mit dem höchsten bit starten)
; high low an sclk(serial clock) nächstes bit.....dann Nsel wieder auf high
rfninit:
;folgende init werte zum übertragen
;Empfänger:
;0x80E7       868mhz, RX fifo TX buffer 12pf
;0x8280       enable receiver
;0xA640       868mhz center freq
;0xC647       19,2kbaud
;0x95A2       Max empfangsstärke 200khz pin als VDI pin
;0xC2AC       digitaler fehlerbehebung
;0xCA81    
;0xC483
;0x9850       TX controll
;0xE000
;0xC800
;0xC040
;KOmmando  0xB000 read 8 bits from fifoRX
;kommando 0xB8xx   send 8 bits of data
ldi ZL, 0xD0           ;Dies ist die Adress welche ich unten als startadresse
ldi ZH, 0x03           ; für die Kommandowords festgelegt habe
ldi temp3, 13
commandloop:
LPM msb, Z               ;läd das erst byte aus diesem Speicherbereich in msb und inc den
LPM lsb, Z               ;Z Pointer anschließend um 1
dec temp3
brne commandloop

rcall send_command

ret


usi_init:
;;USIWM1 und 0 für SPI

;; 0       1
ret

int0_init:
        ldi temp1,(1<<ISC01)|(0<<ISC00)
        out mcucr,temp1
        ldi temp1, (1<<INT0)
        out GIMSK,temp1
        ret

inittimer0:
       sbr temp1, TOIE0
       out TIMSK, temp1
       ldi temp1,0b00000111   ;max prescaler...bei 1mhz 255*1024=262144 takte
                               ; was bei 1 mhz 1/4sek ist
       out TCCR0B, temp1
       ret
;****************************************************************
;INTERRUPTHANDLERS
;****************************************************************
Ext0_int_handle:
;;Daten stehen bereit
;;Auslesen
rcall read_byte
reti

Timer0OFL:
inc counter
cpi counter, 229
brne schlafen
cpi counter, 229
breq wach
reti

schlafen:
;sleep
ret
wach:
clr counter
ret

.org 0x03D0
receiversettings:
.dw 0x80E7
receiverenable:
.dw 0x8280
centerfreq:
.dw 0xA640
setrfmbaud:
.dw 0xC647
recpwr:
.dw 0x95A2
errcorr:
.dw 0xC2AC
unknown1:
.dw 0xCA81
unknown2:
.dw 0xC483
txcontrol:
.dw 0x9850
unknown3:
.dw 0xE000
unknown4:
.dw 0xC800
unknown5:
.dw 0xC040



.include "stddelay.inc"
 
Zuletzt bearbeitet:
Nun habe ich noch etwas versucht aber er scheind in der init schleife fest zu hängen..
Weitere recherchen mit ein paar leds zur signalisierung wo er ca ist und dem terminalt zeigen. Das das RFM immer den wert 0000 empfängt und er seltsamerweise immer nach der empfangsroutine den hallo string am usart ausgibt.(ok das mit dem hallo is gelöst. war mein persöhnlicher fehler:D

warum das RFM nur "000" zurück gibt ist mir schleierhaft
 

Anhänge

  • Unbenannt.jpg
    Unbenannt.jpg
    339,7 KB · Aufrufe: 2
Zuletzt bearbeitet:
Nun habe ich noch etwas versucht aber er scheind in der init schleife fest zu hängen..

Das kommt wahrscheinlich vom Main-Loop ...

rcall hallo



CodeBox Assembler
loop:
rcall hallo
mov data, lsb
;sleep
rcall read_byte
cp data, lsb
breq loop
mov temp1, lsb
rcall seroutdez
rjmp loop


Wegen der Initialisierung über eine Tabelle im Flash ... das ist schon eleganter, aber ich würde doch erst mal das Programm so lassen und austesten und danach ggf. verbessern. Für die Funktion des Programms ist das unwichtig und eventuell baust du dir hier noch einen Fehler rein

Fehler wäre hier zB dass du den Adresspointer Z nicht inkremtierst (postincrement)

LPM r16, Z+
LPM r17, Z+

... also besser eins nach dem anderen.

Ich würde auch keine absolute Adresse für die Tabelle vorgeben. So musst du ja immer drauf achten, dass dort dein Programm nicht "reinläuft".
Die Tabelle einfach irgendwo am besten am Ende deines Programms und über Label adressieren:



CodeBox Assembler
ldi zl, low(2*MeineTabelle)
ldi zh, high(2*MeineTabelle)
lpm

;...
MeineTabelle:
dw 0x1234
dw ....


EDIT
warum das RFM nur "000" zurück gibt ist mir schleierhaft

Das sollte garnicht passieren, da du ja führende Nullen unterdrückst. Für mich ist es jetzt zu spät mir das näher anzusehen.
Probiere doch einfach mal mit festen Werten für temp1 und teste die Funktion seroutdez.
 
Zuletzt bearbeitet:
Hab eigentlich keine Zeit, deswegen nur ein paar kurze Stichpunkte:
  • die feste Adresse für die Tabelle war ein Vorschlag von mir um sicherzustellen, daß alle Tabellen-Bytes dieselbe High-Adresse bekommen, und man sich das beladen von ZH sparen könnte -> vorerst unwichtig. Irgendwo stehen die Daten ja eh im Flash, also kann man sie auch ganz ans Ende setzen. -> egal erstmal.
  • Da Du in der Tabelle jedem Kommando einen Label gegeben hast, kannst Du diesen Label auch zum beladen des Z-Pointers beim Aufruf nutzen (siehe Dirk)
  • Deine LPMs (300,301) sollten ja mit postincrement sein, Du verwendest die aber ohne (müßte irgendwas wie "LPM destinationregister, Z+" sein)
  • Wenn diese Daten nur einmal (init) verwendet werden, ist der allererste Vorschlag über "LDI" am effizientesten -> hattest Du ja quasi so, mein Vorschlag war diesbezüglich, die konkreten Word-Zahlenwerte als Compilervariablen (.equ) anzulegen (sozusagen statt der Kommentare), und dann für die LDIs dann nicht die Hex-Werte zu schreiben, sondern die Variablennamen. Der resultierende Code ist derselbe, aber es wird übersichtlicher, und wenn ein Hex-Kommando/wert nicht stimmt, kannst Du ihn an einer Stelle (beim .equ) verändern.
  • Nach dem Init verwendest Du nur noch zwei Kommandos, das zum lesen aus dem FIFO, und das zum Schreiben, korrekt?
  • Wenn das Init mit einzelnen LDIs realisiert wird (also die Werte im LDI stehen), ist es Quatsch die Bytes erst je in ein High und Lowregister zu laden, und dann in der sendcommand je (nacheinander) in ein Tempregister umzuladen und von dort zu senden. Dann kannst Du die auch gleich Byteweise ins Temp laden und das senden Callen.
Also die Empfehlung wäre, das Init (wieder) mit LDIs zurealisieren - sorry, daß ich Dich da auf den anderen Weg geschickt habe...
 
Kein Problem @LotadaC . Ich heb mir ja sowieso einiges an codeschnnipsel immer für evnetuelle änderungen auf(Auch den ldi Teil). DAs mit dem Zpointer:
Ich habe es gestern noch in postincrement geändert. Funktionieren tut es an sich genau so. Ich habe ein paar LED`s zur überwachung mit iengebaut um zu sehen wo "der kleine kerl" gerade ist. den loop erreicht er und versucht auch immer etwas zu empfangen. den wert den er bekommt ist leider immer 0. Ob es jetzt and er Init liegt oder am Sender ist natürlich wieder die 2 te frage. Das Senderprogramm hab ich auch geändert, den es hätte nie den FRM initialisiert sondern wäre direkt in den loop gesprungen.
Im loop wird eigentlich nur nach einem delay(um nicht 100000 werte zu erhalten die mommentan eh keinen sinn ergeben) empfangen. Das Ergebniss wird an den USART gegeben und gesendet. Mehr ist das im momment nicht. Der intterupt den ich vom RFM erwarte und am INT0 abgreife tritt leider nie ein.
Leider wird der code durch das ganze testen immer aufgeblähter. So umfasst er jetzt ca 600Byte im Hex.



CodeBox Assembler
;;;Kleines Testprogramm
;;Tiny2313 als empfänger
;;Empfängt ein Byte und gibt dieses via usart aus
;;USI als SPI Master
;;interruptausgang von RFM an INT0
;;SPI standartverdrahtung
;;
.list
.include "tn2313def.inc"

.nolist
.equ XTAL=1000000
.equ t5ms = ( XTAL * 5 / 606 ) / 1000

.def temp1=r16
.def temp2=r17
.def temp3=r18
.def data=r19
.def lsb=r21
.def msb=r22
.def datain=r23
.org 0x0000
.equ spiddr=ddrb
.equ spiport=portb
.equ nsel=0
.def counter=r20
.equ debugport=portd       ;Nur zu testzwecken
.equ debugddr=ddrd
rjmp start
.org 0x0001
   rjmp Ext0_int_handle


.org 0x020




start:
ldi temp1, low(ramend)
out spl, temp1                           ;Stackpointer init
ldi temp1, 0xFF
out debugddr, temp1
sbi spiddr, nsel
                           ;RFM12 inittialisiert und bereit("hoffentlich")
rcall delay100ms           ; nach dirk kleines delay um den externen geräten zeit zu geben
rcall initrs232
rcall hallo
rcall int0_init
rcall rfninit
sei
sbi debugport, 3
sbi debugport, 4
;sbi debugport, 5
out debugport, temp1           ; Led an portd2 als anzeige das die initreoutinen durchlaufen wurden

rjmp loop


loop:
rcall delay1s
rcall wert
mov data, lsb
;sleep
cbi debugport, 4
rcall read_byte
rcall delay100ms
sbi debugport, 4               ;Led zeigt an das read routine durchlaufen wurde
;cp data, lsb
;breq loop
mov temp1, lsb
rcall seroutdez
rjmp loop



;**********************************************
;UNTERPROGRAMME
;**********************************************
send_byte:
push lsb
;sender einschalten
ldi msb, 0x82
ldi lsb, 0x20
rcall send_command
;DATENBIT MUSS IN LSB Stehen
ldi msb, 0xB8
push lsb
ldi lsb, 0xAA               ;präambel
rcall send_command
rcall send_command
;;nun das synchronbyte
ldi lsb, 0x2D
rcall send_command
ldi lsb, 0xD4
rcall send_command
;;nun die nutzdaten
pop lsb
rcall send_command
;Zeit geben
rcall delay100ms
;sender wider ausschalten und empfänger an
ldi msb, 0x82
ldi lsb, 0x80
pop lsb                       ;16.12.2016
rcall send_command

ret

read_byte:
;;DATENBYTE befindet sich in LSB
ldi msb, 0xB0
ldi lsb, 0x00
rcall send_command
in lsb, USIDR
ret

send_command:
mov temp1, msb
cbi spiport,nsel
nop nop nop nop           ;Zu testzwecken nach Dirk ein kleines delay
nop nop nop nop
rcall SPITransfer
mov temp1, lsb
rcall SPITransfer
sbi spiport,nsel

ret




SPITransfer:
out    USIDR,temp1
ldi    r16,(1<<USIOIF)
out    USISR,r16
ldi    r17,(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)

SPITransfer_loop:
out    USICR,r17
in     r16, USISR
sbrs   r16, USIOIF
rjmp   SPITransfer_loop
in     temp1,USIDR
ret

ret
;******************************************************************
;RS232 Routine
;******************************************************************
initrs232:
.equ takt = 1000000 ; 16/8 MHz Systemtakt
.equ baud =2400   ; Baudrate
.equ ubrr_val = ((takt+baud*8)/(baud*16)-1)   ; clever Runden
.equ baud_real = (takt/(16*(ubrr_val+1)))   ; tatsächliche Baudrate
.equ baud_error = ((baud_real*1000)/baud-1000)   ; Fahler in Promille
;
;
.if ((baud_error> 10) || (baud_error <-10))       ; max +/- 10 Promill Fehler
   .error "Systematischer Fehler der Baudrate größer als 1 Prozent und damit zu hoch!"
.else
   .message "Systematischer Fehler der Baudrate hält sich in Grenzen - OK!"
.endif
rcall serinit
rcall hallo
ret

seroutdez:
           push  temp1            ; die Funktion verändert temp1 und temp2,
           push  temp2            ; also sichern wir den Inhalt, um ihn am Ende
                                  ; wieder herstellen zu können

           mov   temp2, temp1     ; das Register temp1 frei machen
                                  ; abzählen wieviele Hunderter
                                  ; in der Zahl enthalten sind
;** Hunderter **
           ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen
number_1:
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
                                  ; Durchlauf eine '0' in temp1)
           subi  temp2, 100       ; 100 abziehen
           brcc  number_1     ; ist dadurch kein Unterlauf entstanden?
                                  ; nein, dann zurück zu lcd_number_1
           subi  temp2, -100      ; 100 wieder dazuzählen, da die
                                  ; vorherhgehende Schleife 100 zuviel
                                  ; abgezogen hat
           cpi temp1, 0           ;Führende null weg
           breq number_2
           rcall serout        ; die Hunderterstelle ausgeben

;** Zehner  **
           ldi   temp1, '0'-1     ; temp1 mit ASCII '0'-1 vorladen
number_2:
           inc   temp1            ; ASCII erhöhen (somit ist nach dem ersten
                                  ; Durchlauf eine '0' in temp1)
           subi  temp2, 10        ; 10 abziehen
           brcc  number_2     ; ist dadurch kein Unterlauf enstanden?
                                  ; nein, dann zurück zu lcd_number_2
           subi  temp2, -10       ; 10 wieder dazuzählen, da die
                                  ; vorherhgehende Schleife 10 zuviel
                                  ; abgezogen hat
           cpi temp1, 0           ;Führende null weg
           breq number_3
           rcall serout        ; die Zehnerstelle ausgeben
;** Einer **       
number_3:
           ldi   temp1, '0'       ; die Zahl in temp2 ist jetzt im Bereich
           add   temp1, temp2     ; 0 bis 9. Einfach nur den ASCII Code für
           rcall serout         ; '0' dazu addieren und wir erhalten dierekt
                                  ; den ASCII Code für die Ziffer


           pop   temp2            ; den gesicherten Inhalt von temp2 und temp1
           pop   temp1            ; wieder herstellen
           ret                    ; und zurück


wert:
ldi temp1, 'W'
rcall serout
ldi temp1, 'e'
rcall serout
ldi temp1, 'r'
rcall serout
ldi temp1, 't'
rcall serout
ldi temp1, ';'
rcall serout
ldi temp1, ' '
rcall serout



hallo:
ldi temp1, 'O'
rcall serout
ldi temp1, 'K'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, 'R'
rcall serout
ldi temp1, 'S'
rcall serout
ldi temp1, ' '
rcall serout
ldi temp1, '2'
rcall serout
ldi temp1, '3'
rcall serout
ldi temp1, '2'
rcall serout
ret

serout:
   sbis ucsra,udre                   ; udre-bit ist gesetzt, wenn der Sendepuffer leer ist
                                   ; UART Data Register Empty
   rjmp serout
   out    udr, temp1                   ; Zeichen senden
   ret                               ; zurück aus der Subroutine

   ; Zeichen über RS232 einlesen
   ; temp1: gibt das Zeichen zurück
serin:
   sbis ucsra, rxc   
   rjmp serin                       ; wir warten bis ein Byte angekommen ist

   in temp1, udr                   ; Zeichen einlesen
   ;rcall serout                   ; und zurücksenden   
   ret

   ; Zeichen über RS232 einlesen und als Echo zurücksenden
   ; temp1: gibt das Zeichen zurück


serinit:
   ; Baudrate für RS232 einstellen
   ldi temp1, high(ubrr_val)       ; zuerst Baudrate Highbyte (davon Lownibble)
   out ubrrh, temp1
   ldi temp1, low(ubrr_val)           ; Lowbyte schreiben und prescaler damit triggern
   out ubrrl, temp1

   ; frameformat setzen
   ldi temp1, (1<<ucsz1) | (1<<ucsz0)   ; ucsz2:0 = 0 1 1 -> 8 Bit Daten, kein Parity, 1 Stopbit
   out ucsrc, temp1

   ; Transmitter einschalten, PortD Bit1 wird überschrieben
   sbi ucsrb, txen                   ; TXE-Bit (3) setzen
   
   ; Receiver einschalten, PortD Bit0 wird überschrieben
   sbi ucsrb, rxen                   ; RXE-Bit (4) setzen
   ;sbi ucsrb, rxcie               ; RXCIE-bit (7) setzen, damit ein irq ausgelöst werden kann, wenn ein Zeichen da ist
   ret



;***********************************************************
;INITS
;***********************************************************
;;Nsel auf low einen momment warten dann bit an SDI vom modul(mit dem höchsten bit starten)
; high low an sclk(serial clock) nächstes bit.....dann Nsel wieder auf high
rfninit:
;folgende init werte zum übertragen
;Empfänger:
;0x80E7       868mhz, RX fifo TX buffer 12pf
;0x8280       enable receiver
;0xA640       868mhz center freq
;0xC647       19,2kbaud
;0x95A2       Max empfangsstärke 200khz pin als VDI pin
;0xC2AC       digitaler fehlerbehebung
;0xCA81       
;0xC483
;0x9850       TX controll
;0xE000
;0xC800
;0xC040
;KOmmando  0xB000 read 8 bits from fifoRX
;kommando 0xB8xx   send 8 bits of data
ldi msb, 0x80
ldi lsb, 0xE7
rcall send_command
ldi msb, 0x82
ldi lsb, 0x80
rcall send_command
ldi msb, 0xA6
ldi lsb, 0x40
rcall send_command
ldi msb, 0xC6
ldi lsb, 0x47
rcall send_command
ldi msb, 0x95
ldi lsb, 0x82
rcall send_command
ldi msb, 0xc2
ldi lsb, 0xAC
rcall send_command
ldi msb, 0xCA
ldi lsb, 0x81
rcall send_command
ldi msb, 0xc4
ldi lsb, 0x83
rcall send_command
ldi msb, 0x98
ldi lsb, 0x50
rcall send_command
ldi msb, 0xE0
ldi lsb, 0x00
rcall send_command
ldi msb, 0xC8
ldi lsb, 0x00
rcall send_command
ldi msb, 0xC0
ldi lsb, 0x40
rcall send_command
ret


int0_init:
        ldi temp1,(1<<ISC01)|(0<<ISC00)
        out mcucr,temp1
        ldi temp1, (1<<INT0)
        out GIMSK,temp1
        ret

;****************************************************************
;INTERRUPTHANDLERS
;****************************************************************
Ext0_int_handle:
;;Daten stehen bereit
;;Auslesen
rcall read_byte
reti

.include "stddelay.inc"

 
Hier noch einmal der sender:


CodeBox Assembler

.include "tn44def.inc"
.def temp1=r16
.def temp2=r17
.def temp3=r18
.def datain=r19
.equ spiport=porta
.equ spiddr=ddra
.def lsb= r20
.def msb=r21
.equ XTAL=1000000
.equ t5ms = ( XTAL * 5 / 606 ) / 1000
.equ nsel=3
start:
ldi temp1, high(ramend)
out sph, temp1
ldi temp1, low(ramend)
rcall delay1s
out spl, temp1                           ;Stackpointer init
sbi spiddr, nsel
rcall rfninit                           ;RFM12 inittialisiert und bereit("hoffentlich")
rjmp loop

loop:
inc r22
lsl r22
mov lsb, r22
rcall send_byte
rcall delay1s
rjmp loop


;;;;;;;;;;;;;;;;;;;;;UNTERPROGRAMME


rfninit:
;folgende init werte zum übertragen
;Empfänger:
;0x80E7       868mhz, RX fifo TX buffer 12pf
;0x8280       enable receiver
;0xA640       868mhz center freq
;0xC647       19,2kbaud
;0x9582       Max empfangsstärke 200khz pin als VDI pin
;0xC2AC       digitaler fehlerbehebung
;0xCA81       
;0xC483
;0x9850       TX controll
;0xE000
;0xC800
;0xC040
;KOmmando  0xB000 read 8 bits from fifoRX
;kommando 0xB8xx   send 8 bits of data
rcall delay1s
ldi msb, 0x80
ldi lsb, 0xE7
rcall send_command

ldi msb, 0x82
ldi lsb, 0x80
rcall send_command

ldi msb, 0xA6
ldi lsb, 0x40
rcall send_command

ldi msb, 0xC6
ldi lsb, 0x47
rcall send_command

ldi msb, 0x95
ldi lsb, 0x82
rcall send_command

ldi msb, 0xc2
ldi lsb, 0xAC
rcall send_command

ldi msb, 0xCA
ldi lsb, 0x81
rcall send_command

ldi msb, 0xc4
ldi lsb, 0x83
rcall send_command

ldi msb, 0x98
ldi lsb, 0x50
rcall send_command

ldi msb, 0xE0
ldi lsb, 0x00
rcall send_command

ldi msb, 0xC8
ldi lsb, 0x00
rcall send_command

ldi msb, 0xC0
ldi lsb, 0x40
rcall send_command

ret


send_byte:
push lsb
;sender einschalten
ldi msb, 0x82
ldi lsb, 0x20
rcall send_command
;DATENBIT MUSS IN LSB Stehen
ldi msb, 0xB8
push lsb
ldi lsb, 0xAA               ;präambel
rcall send_command
rcall send_command
;;nun das synchronbyte
ldi lsb, 0x2D
rcall send_command
ldi lsb, 0xD4
rcall send_command
;;nun die nutzdaten
pop lsb
rcall send_command
;Zeit geben
rcall delay100ms
;sender wider ausschalten und empfänger an
ldi msb, 0x82
ldi lsb, 0x80
rcall send_command

ret

read_byte:
;;DATENBYTE befindet sich in LSB
ldi msb, 0xB0
ldi lsb, 0x00
rcall send_command
in lsb, USIDR
ret

send_command:
mov temp1, msb
cbi spiport,nsel
rcall SPITransfer
mov temp1, lsb
rcall SPITransfer
sbi spiport,nsel

ret




SPITransfer:
out    USIDR,temp1
ldi    r16,(1<<USIOIF)
out    USISR,r16
ldi    r17,(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC)

SPITransfer_loop:
out    USICR,r17
in     r16, USISR
sbrs   r16, USIOIF
rjmp   SPITransfer_loop
in     temp1,USIDR
ret

.include "stddelay.inc"



Ich danke euch sehr das ihr mir helft eine eventuelle lösung zu finden.
Daniel
 
Hallo,

beim Sender hast du send_byte noch nicht korrigiert.
Dein Programm stürzt hier sofort ab beim return.

Es fehlt noch ein pop.

Beim Empfänger hast du send_byte zwar korrigiert, allerdings an einer falschen Stelle und die Routine send_byte wird ja hier nicht genutzt.



CodeBox Assembler
ldi msb, 0x82
ldi lsb, 0x80
pop lsb                      ;16.12.2016
rcall send_command


lsb wird hier überschrieben, das ist sicher nicht beabsichtigt.
 
:D danke dirk hate ich ganz vergessen. Nun habe ich das Programm des 2313 so geändert das er mir den status des rfm vor jedem wert auslesen soll und via RS232 ausgeben. das command hierfür ist 0x0000 gleichzeitig kommt der spi der status in 2 Bytes rein.
leider scheint die kommunikation zwischen tiny und rfm12 überhaupt nicht zu funktionieren dar das statusregister nichts ausgibt. Also vermute ich einen fehler in der kommunikation via USI.

Mir tut es so leid das ihr euch mit so etwas chaotischem rumschlagen müsst :-(

PS: SDI und SDO pin des rfm habe ich testweise auch schon getauscht ohne erfolg. Also scheint das usi überhautp nicht das zu machen was es soll
 
Ich komme leider nicht dazu, mich näher mit dem RFM12 zu befassen. Bist du dir sicher, dass die Initialisierung stimmt? (Ich versuche mir das morgen nochmal weiter anzuschauen)

Ich würde folgendes machen, um die Kommunikation zwischen Mikrocontroller und RFM12 zu testen. Gibt es ein Register im RFM12, welches du auslesen kannst und dessen Wert du kennst? Wenn ja, einfach mal nur das den Inhalt des Registers lesen und prüfen, so hast du schon mal SPI überprüft.

SDI und SDO falsch anschließen ist nicht so gut, da hier zwei Ausgänge gegeneinander arbeiten (zwei SDO verbunden).

Dirk :ciao:
 
Hallo Dirk. Die initialisierung ist doch recht komplex. Meine beruht auf Standart werten. Es gibt ein Statusregister welches man mit 0x0000 auslesen kann. Leider nur nach einer erfolgreichen initialisierung, zu der es anscheinend ja nicht kommt. Ich habe das Datenblatt vor mir liegen. Das Problem ist das irgendwann der kopf zu macht. Das ganze stiftet doch sehr große verwirru. Allein die Tatsache das nirgens die genau Pinfunktion erleutert ist und eine vorgehensweise, woher man weis das das Modul bereit ist angesprochen zu werden oder ausgelsen. Ich werde noch einmal einen kleinen tiny85 damit quälen um eine komunikation mit dem Modul zu testen. Vom 44 welchen ich dann später für den sensor brauche habe ich nur einen und der letzte frei 2313(ohne etwas bestehendes zu zerlegen) ist hier in gebrauch. Ich denke mal das USI=USI egal welcher kontroller.

Ich bin jetzt erstmal zum essen geladen ;)
Ich werde versuchen heute evtl auch hierzu noch einen beitrag hier zu leisten

Daniel :wink:
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)