Serieller Datenempfang im Interrupt / "Bascom"

Hallo laplace,

mit einer "krummen" Taktfrequenz geht so ziemlich alles. Schau doch mal hier. Vielleicht ist das die Lösung. 18.432MHz sollte problemlos funktionieren, aber auch 3.6864MHz.
Mit richtig übler Übertaktung hat Dino ja schon einige Erfahrung.


Grüsse,

Michael
 
Mal ein erstes Ergebnis mit reinem BASCOM und direktem Zugriff auf die
Register bei nem Mega32 auf nem nachgebauten Pollin-Board ...

Die Anzeige auf dem LCD ...
P1040254.JPG

So sieht das Board aus ...
P1040256.JPG

und ich hab Pin2+3 der RS232 verbunden damit das Board die
eigenen Daten wieder empfängt ...
P1040257.JPG

Es werden alle 100ms zweimal das Eingangsregister gelesen und
danach ein Byte gesendet. Das erst einmal fürs erste. Bis 250kBit
gibt es keine Datenprobleme. Als nächstes teste ich mit nem PC ...

Hier der Quellcode wie er beim Test mit 250kBit aussieht ...
Anhang anzeigen L06_RS232.bas



CodeBox BASCOM

' Testprogramm für mein Pollin-Nachbau-Board

' #############################################################################
' ##### Definitionen ##########################################################
' #############################################################################

' Prozessor ATmega8535 (lag grade so rum)
' 8k Flash, 512Byte SRAM, 512Byte EEPROM
' $regfile = "m8535.dat"

' Prozessor ATmega16 (wers braucht)
' $regfile = "m16def.dat"

' Prozessor ATmega32 (wers braucht)
$regfile = "m32def.dat"

' 16MHz Quarztakt
$crystal = 16000000

' Hab ich abgekupfert ;-)
$hwstack = 32
$swstack = 10
$framesize = 40


' #############################################################################
' ##### Variablen #############################################################
' #############################################################################

' Was Byte-mässiges
Dim A As Byte
A = 0
Dim B As Byte
B = 0
Dim C As Word
C = 0


' #############################################################################
' ##### Initialisierung #######################################################
' #############################################################################


' ==============================================
' Die Ports auf dem Eval-Board und ihre Belegung
' ==============================================

' DDRx => Datenrichtung des Portpins
' 0=Eingang , 1=Ausgang

' PORTx => Ausgang oder PullUp
' 0=GND/PullUp aus , 1=Vcc/PullUp an

' PINx => Eingang (Pin abfragen)

' === PortA ============================
' PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0
' - - - - - - - -
' Alle Portbits können verwendet werden
Ddra = &B1111_1111
Porta = &B0000_0000
' ======================================

' === PortB ============================
' PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0
' SCK MOSI MISO - - - - -
' Alle Portbits können verwendet werden
' Bei PB5..7 aber Einschränkung wegen ISP
Ddrb = &B1111_1111
Portb = &B0000_0000
' ======================================

' === PortC ============================
' PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0
' - - - - - - SDA SCL
' Alle Portbits können verwendet werden
' Bei I2C-Bus (TWI) sind PC0+1 aber belegt
Ddrc = &B1111_1111
Portc = &B0000_0000
' ======================================

' === PortD ============================
' PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0
' Buz LD2 LD1 T3 T2 T1 TxD RxD
' Hier sind beim Eval-Board Taster, LEDs
' Buzzer und RS232 dran
Ddrd = &B1110_0000
Portd = &B0000_0000
' ======================================
' ======================================
' ======================================


' ======================================
' === LCD-Initialisierung ==============
' ======================================
' Umschaltbyte für Anzeige : 0 = Chip 1 / 1 = Chip 2
Dim ___lcdno As Byte
' with the config lcdpin statement you can override the compiler settings
Config Lcd = 40 * 4

' LCD an PORT-A
Config Lcdpin = Pin , Db4 = Porta.0 , Db5 = Porta.1 , Db6 = Porta.2 , Db7 = Porta.3 , E = Porta.4 , E2 = Porta.5 , Rs = Porta.6

Config Lcdbus = 4

' === oberen Chip 1 einschalten und initialisieren ===
___lcdno = 0
Initlcd
Cls
' === unteren Chip 2 einschalten und initialisieren ===
___lcdno = 1
Initlcd
Cls

___lcdno = 0 ' zurueck auf oberen Chip

' ======================================
' ======================================
' ======================================

' UBRRL - USART Baud Rate Register Low Byte
' * Bit 0..7 : USART Baud Rate Register bit 0..7

' UBRRH - USART Baud Rate Register High Byte
' * Bit 0 : USART Baud Rate Register bit 8
' * Bit 1 : USART Baud Rate Register bit 9
' * Bit 2 : USART Baud Rate Register bit 10
' * Bit 3 : USART Baud Rate Register bit 11
' * Bit 4 : 0
' * Bit 5 : 0
' * Bit 6 : 0
' * Bit 7 : USRSEL (Register Select) 1=UCSRC 0=UBRRH
' bei UX2=1 und 16MHz Takt
' H L delta H L delta
' 1k2 1666 6 130 0,0% 38k4 51 0 51 +0,2%
' 2k4 832 3 64 0,0% 57k6 34 0 34 -0,8%
' 4k8 416 1 160 -0,1% 115k2 16 0 16 +2,1%
' 9k6 207 0 207 +0,2% 230k4 8 0 8 -3,5%
' 19k2 103 0 103 +0,2% 250k0 7 0 7 0,0%
C = 7 ' fuer Ausgabe auf LCD
Ubrr = C

' UCSRA - USART Control and Status Register A
' * Bit 0 : MPCM Multi-processor Communication Mode
' * Bit 1 : U2X Double the USART transmission speed
' * Bit 2 : UPE Parity Error
' * Bit 2 : PE = UPE For compatibility
' * Bit 3 : DOR Data overRun
' * Bit 4 : FE Framing Error
' * Bit 5 : UDRE USART Data Register Empty
' * Bit 6 : TXC USART Transmitt Complete <===
' * Bit 7 : RXC USART Receive Complete <===
' 0b00000010 ; U2X=1
Ucsra = &B0000_0010

' UCSRC - USART Control and Status Register C
' * Bit 0 : UCPOL Clock Polarity
' * Bit 1 : UCSZ0 Character Size Bit 0
' * Bit 2 : UCSZ1 Character Size Bit 1
' * Bit 3 : USBS Stop Bit Select 0 = 1Stop-Bit , 1 = 2 Stop-Bits
' * Bit 4 : UPM0 Parity Mode Bit 0
' * Bit 5 : UPM1 Parity Mode Bit 1
' * Bit 6 : UMSEL USART Mode Select Async=0 Sync=1
' * Bit 7 : URSEL Register Select
'
' UPM 00 Disabled UCSZ 000 5-Bit , 100 Reserved
' 01 Reserved 001 6-Bit , 101 Reserved
' 10 Even Parity 010 7-Bit , 110 Reserved
' 11 Odd Parity 011 8-Bit , 111 9-Bit
'
' SyncMode TxD Changed RxD Sampled
' UCPOL 0 Rising XCK Edge Falling XCK Edge
' 1 Falling XCK Edge Rising XCK Edge
' 0b10000110 ; URSEL=1 (UCSRC) , USBS=0 UCSZ=3 => Frame-Format 8Bit/1Stop
Ucsrc = &B10000110

' UCSRB - USART Control and Status Register B
' * Bit 0 : TXB8 Transmit Data Bit 8
' * Bit 1 : RXB8 Receive Data Bit 8
' * Bit 2 : UCSZ2 Character Size Bit 2
' * Bit 2 : CHR9 = UCSZ2 For compatibility
' * Bit 3 : TXEN Transmitter Enable
' * Bit 4 : RXEN Receiver Enable
' * Bit 5 : UDRIE USART Data register Empty Interrupt Enable
' * Bit 6 : TXCIE TX Complete Interrupt Enable <===
' * Bit 7 : RXCIE RX Complete Interrupt Enable <===
' r18,0b00011000 ; UCSZ2=0 (8Bit) , TXEN + RXEN => Enable Receiver/Transmitter
Ucsrb = &B00011000


Locate 1 , 1
Lcd "Moins UBRR : " ; C

' #############################################################################
' ##### Hauptschleife #########################################################
' #############################################################################

Do

Waitms 100

___lcdno = 0 ' zurueck auf oberen Chip
Locate 2 , 7
A = Ucsra ' Skip if Bit 5 is Set : UDRE USART Data Register Empty
B = Udr
Lcd "Rx:" ; Bin(a) ; " " ; Bin(b)

___lcdno = 1 ' auf unteren Chip
Locate 1 , 7
A = Ucsra ' Skip if Bit 5 is Set : UDRE USART Data Register Empty
B = Udr
Lcd "Rx:" ; Bin(a) ; " " ; Bin(b)

Locate 2 , 7
A = Ucsra ' Skip if Bit 5 is Set : UDRE USART Data Register Empty
B = &H55
Udr = B
Lcd "Tx:" ; Bin(a) ; " " ; Bin(b)

Toggle Portd.5

Loop


' #############################################################################
' ##### Interrupt-Service-Routinen ############################################
' #############################################################################



' #############################################################################
' ##### Subroutinen ###########################################################
' #############################################################################



End

' #############################################################################
' ##### Programmende ##########################################################
' #############################################################################


Gruß
Dino
 
USB-Dongle mit 230k4-8n1 fehlerfrei

Hier mal ein Bild ...

PuTTY_230k4.gif

Die ersten Zeichen sind mit 38k4 wobei das Terminal schon auf 230k4 steht.
Die UUUUUUU kommen dann mit 230k4 von Mega32 über den MaX232.

Der Atmel schickt jetzt alle 10ms ein Zeichen mit 230k4 8n1 und es läuft
fehlerfrei. Die gesendeten Zeichen vom PC sehe ich auch im UDR-Register
ankommen. Auch mit dem richtigen Wert (zB Leerzeichen mit 20h).

Das ist allerding im Moment noch alles ohne Interrupts und Umstellung der
Baudrate im Betrieb. Aber das sollte auch kein Thema sein ... :D

Gruß
Dino
 
115k2 8n1 ohne Wait senden - fehlerfrei

Die letzten Grütz-Zeichen stammen vom Abziehen des Dongles damit ich eine
saubere Hardcopy ziehen kann ...
PuTTY_115k2_no-wait.gif
Das waren 115k2 8n1 vom Atmel zum PuTTY mit +2,1% Abweichung im
Datentakt.

Das Programm ...


CodeBox BASCOM

' Testprogramm für mein Pollin-Nachbau-Board

' #############################################################################
' ##### Definitionen ##########################################################
' #############################################################################

' Prozessor ATmega8535 (lag grade so rum)
' 8k Flash, 512Byte SRAM, 512Byte EEPROM
' $regfile = "m8535.dat"

' Prozessor ATmega16 (wers braucht)
' $regfile = "m16def.dat"

' Prozessor ATmega32 (wers braucht)
$regfile = "m32def.dat"

' 16MHz Quarztakt
$crystal = 16000000

' Hab ich abgekupfert ;-)
$hwstack = 32
$swstack = 10
$framesize = 40


' #############################################################################
' ##### Variablen #############################################################
' #############################################################################

' Was Byte-mässiges
Dim A As Byte
A = 0
Dim B As Byte
B = 0
Dim C As Word
C = 0
Dim D As Byte
D = 32

' #############################################################################
' ##### Initialisierung #######################################################
' #############################################################################


' ==============================================
' Die Ports auf dem Eval-Board und ihre Belegung
' ==============================================

' DDRx => Datenrichtung des Portpins
' 0=Eingang , 1=Ausgang

' PORTx => Ausgang oder PullUp
' 0=GND/PullUp aus , 1=Vcc/PullUp an

' PINx => Eingang (Pin abfragen)

' === PortA ============================
' PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0
' - - - - - - - -
' Alle Portbits können verwendet werden
Ddra = &B1111_1111
Porta = &B0000_0000
' ======================================

' === PortB ============================
' PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0
' SCK MOSI MISO - - - - -
' Alle Portbits können verwendet werden
' Bei PB5..7 aber Einschränkung wegen ISP
Ddrb = &B1111_1111
Portb = &B0000_0000
' ======================================

' === PortC ============================
' PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0
' - - - - - - SDA SCL
' Alle Portbits können verwendet werden
' Bei I2C-Bus (TWI) sind PC0+1 aber belegt
Ddrc = &B1111_1111
Portc = &B0000_0000
' ======================================

' === PortD ============================
' PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0
' Buz LD2 LD1 T3 T2 T1 TxD RxD
' Hier sind beim Eval-Board Taster, LEDs
' Buzzer und RS232 dran
Ddrd = &B1110_0000
Portd = &B0000_0000
' ======================================
' ======================================
' ======================================


' ======================================
' === LCD-Initialisierung ==============
' ======================================
' Umschaltbyte für Anzeige : 0 = Chip 1 / 1 = Chip 2
Dim ___lcdno As Byte
' with the config lcdpin statement you can override the compiler settings
Config Lcd = 40 * 4

' LCD an PORT-A
Config Lcdpin = Pin , Db4 = Porta.0 , Db5 = Porta.1 , Db6 = Porta.2 , Db7 = Porta.3 , E = Porta.4 , E2 = Porta.5 , Rs = Porta.6

Config Lcdbus = 4

' === oberen Chip 1 einschalten und initialisieren ===
___lcdno = 0
Initlcd
Cls
' === unteren Chip 2 einschalten und initialisieren ===
___lcdno = 1
Initlcd
Cls

___lcdno = 0 ' zurueck auf oberen Chip

' ======================================
' ======================================
' ======================================

' UBRRL - USART Baud Rate Register Low Byte
' * Bit 0..7 : USART Baud Rate Register bit 0..7

' UBRRH - USART Baud Rate Register High Byte
' * Bit 0 : USART Baud Rate Register bit 8
' * Bit 1 : USART Baud Rate Register bit 9
' * Bit 2 : USART Baud Rate Register bit 10
' * Bit 3 : USART Baud Rate Register bit 11
' * Bit 4 : 0
' * Bit 5 : 0
' * Bit 6 : 0
' * Bit 7 : USRSEL (Register Select) 1=UCSRC 0=UBRRH
' bei UX2=1 und 16MHz Takt
' H L delta H L delta
' 1k2 1666 6 130 0,0% 38k4 51 0 51 +0,2%
' 2k4 832 3 64 0,0% 57k6 34 0 34 -0,8%
' 4k8 416 1 160 -0,1% 115k2 16 0 16 +2,1%
' 9k6 207 0 207 +0,2% 230k4 8 0 8 -3,5%
' 19k2 103 0 103 +0,2% 250k0 7 0 7 0,0%
C = 16 ' fuer Ausgabe auf LCD
Ubrr = C

' UCSRA - USART Control and Status Register A
' * Bit 0 : MPCM Multi-processor Communication Mode
' * Bit 1 : U2X Double the USART transmission speed
' * Bit 2 : UPE Parity Error
' * Bit 2 : PE = UPE For compatibility
' * Bit 3 : DOR Data overRun
' * Bit 4 : FE Framing Error
' * Bit 5 : UDRE USART Data Register Empty
' * Bit 6 : TXC USART Transmitt Complete <===
' * Bit 7 : RXC USART Receive Complete <===
' 0b00000010 ; U2X=1
Ucsra = &B0000_0010

' UCSRC - USART Control and Status Register C
' * Bit 0 : UCPOL Clock Polarity
' * Bit 1 : UCSZ0 Character Size Bit 0
' * Bit 2 : UCSZ1 Character Size Bit 1
' * Bit 3 : USBS Stop Bit Select 0 = 1Stop-Bit , 1 = 2 Stop-Bits
' * Bit 4 : UPM0 Parity Mode Bit 0
' * Bit 5 : UPM1 Parity Mode Bit 1
' * Bit 6 : UMSEL USART Mode Select Async=0 Sync=1
' * Bit 7 : URSEL Register Select
'
' UPM 00 Disabled UCSZ 000 5-Bit , 100 Reserved
' 01 Reserved 001 6-Bit , 101 Reserved
' 10 Even Parity 010 7-Bit , 110 Reserved
' 11 Odd Parity 011 8-Bit , 111 9-Bit
'
' SyncMode TxD Changed RxD Sampled
' UCPOL 0 Rising XCK Edge Falling XCK Edge
' 1 Falling XCK Edge Rising XCK Edge
' 0b10000110 ; URSEL=1 (UCSRC) , USBS=0 UCSZ=3 => Frame-Format 8Bit/1Stop
Ucsrc = &B10000110

' UCSRB - USART Control and Status Register B
' * Bit 0 : TXB8 Transmit Data Bit 8
' * Bit 1 : RXB8 Receive Data Bit 8
' * Bit 2 : UCSZ2 Character Size Bit 2
' * Bit 2 : CHR9 = UCSZ2 For compatibility
' * Bit 3 : TXEN Transmitter Enable
' * Bit 4 : RXEN Receiver Enable
' * Bit 5 : UDRIE USART Data register Empty Interrupt Enable
' * Bit 6 : TXCIE TX Complete Interrupt Enable <===
' * Bit 7 : RXCIE RX Complete Interrupt Enable <===
' r18,0b00011000 ; UCSZ2=0 (8Bit) , TXEN + RXEN => Enable Receiver/Transmitter
Ucsrb = &B00011000


Locate 1 , 1
Lcd "Moins UBRR : " ; C

' #############################################################################
' ##### Hauptschleife #########################################################
' #############################################################################

Do

' Waitms 10

___lcdno = 0 ' zurueck auf oberen Chip
' Locate 2 , 7
A = Ucsra ' Skip if Bit 5 is Set : UDRE USART Data Register Empty
B = Udr
' Lcd "Rx:" ; Bin(a) ; " " ; Bin(b)

___lcdno = 1 ' auf unteren Chip
' Locate 1 , 7
A = Ucsra ' Skip if Bit 5 is Set : UDRE USART Data Register Empty
B = Udr
' Lcd "Rx:" ; Bin(a) ; " " ; Bin(b)

' Locate 2 , 7
A = Ucsra ' Skip if Bit 5 is Set : UDRE USART Data Register Empty
Bitwait Ucsra.5 , Set
B = D
Udr = B
' Lcd "Tx:" ; Bin(a) ; " " ; Bin(b)

' Toggle Portd.5

' Damit nicht immer die selben Zeichen gesendet werden ...
D = D + 1
If D > 120 Then D = 32

Loop


' #############################################################################
' ##### Interrupt-Service-Routinen ############################################
' #############################################################################



' #############################################################################
' ##### Subroutinen ###########################################################
' #############################################################################



End

' #############################################################################
' ##### Programmende ##########################################################
' #############################################################################

was soll ich sagen ... bei mir geht es bis jetzt aucch über 38k4 ... :p
Aber evtl kommt das Problem ja noch ...

Gruß
Dino
 
115k2 Echo-Routine mit reinem BASCOM

PuTTY_115k2_Echo.gif
115k2 Echo-Routine im Atmel vom PC her mit Daten zugeblasen. Es kommt alles
sauber zurück ... (aber noch ohne Interrupt) ...


CodeBox BASCOM

' Testprogramm für mein Pollin-Nachbau-Board

' #############################################################################
' ##### Definitionen ##########################################################
' #############################################################################

' Prozessor ATmega8535 (lag grade so rum)
' 8k Flash, 512Byte SRAM, 512Byte EEPROM
' $regfile = "m8535.dat"

' Prozessor ATmega16 (wers braucht)
' $regfile = "m16def.dat"

' Prozessor ATmega32 (wers braucht)
$regfile = "m32def.dat"

' 16MHz Quarztakt
$crystal = 16000000

' Hab ich abgekupfert ;-)
$hwstack = 32
$swstack = 10
$framesize = 40


' #############################################################################
' ##### Variablen #############################################################
' #############################################################################

' Was Byte-mässiges
Dim A As Byte
A = 0
Dim B As Byte
B = 0
Dim C As Word
C = 0
Dim D As Byte
D = 32

' #############################################################################
' ##### Initialisierung #######################################################
' #############################################################################


' ==============================================
' Die Ports auf dem Eval-Board und ihre Belegung
' ==============================================

' DDRx => Datenrichtung des Portpins
' 0=Eingang , 1=Ausgang

' PORTx => Ausgang oder PullUp
' 0=GND/PullUp aus , 1=Vcc/PullUp an

' PINx => Eingang (Pin abfragen)

' === PortA ============================
' PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0
' - - - - - - - -
' Alle Portbits können verwendet werden
Ddra = &B1111_1111
Porta = &B0000_0000
' ======================================

' === PortB ============================
' PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0
' SCK MOSI MISO - - - - -
' Alle Portbits können verwendet werden
' Bei PB5..7 aber Einschränkung wegen ISP
Ddrb = &B1111_1111
Portb = &B0000_0000
' ======================================

' === PortC ============================
' PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0
' - - - - - - SDA SCL
' Alle Portbits können verwendet werden
' Bei I2C-Bus (TWI) sind PC0+1 aber belegt
Ddrc = &B1111_1111
Portc = &B0000_0000
' ======================================

' === PortD ============================
' PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0
' Buz LD2 LD1 T3 T2 T1 TxD RxD
' Hier sind beim Eval-Board Taster, LEDs
' Buzzer und RS232 dran
Ddrd = &B1110_0000
Portd = &B0000_0000
' ======================================
' ======================================
' ======================================


' ======================================
' === LCD-Initialisierung ==============
' ======================================
' Umschaltbyte für Anzeige : 0 = Chip 1 / 1 = Chip 2
Dim ___lcdno As Byte
' with the config lcdpin statement you can override the compiler settings
Config Lcd = 40 * 4

' LCD an PORT-A
Config Lcdpin = Pin , Db4 = Porta.0 , Db5 = Porta.1 , Db6 = Porta.2 , Db7 = Porta.3 , E = Porta.4 , E2 = Porta.5 , Rs = Porta.6

Config Lcdbus = 4

' === oberen Chip 1 einschalten und initialisieren ===
___lcdno = 0
Initlcd
Cls
' === unteren Chip 2 einschalten und initialisieren ===
___lcdno = 1
Initlcd
Cls

___lcdno = 0 ' zurueck auf oberen Chip

' ======================================
' ======================================
' ======================================

' UBRRL - USART Baud Rate Register Low Byte
' * Bit 0..7 : USART Baud Rate Register bit 0..7

' UBRRH - USART Baud Rate Register High Byte
' * Bit 0 : USART Baud Rate Register bit 8
' * Bit 1 : USART Baud Rate Register bit 9
' * Bit 2 : USART Baud Rate Register bit 10
' * Bit 3 : USART Baud Rate Register bit 11
' * Bit 4 : 0
' * Bit 5 : 0
' * Bit 6 : 0
' * Bit 7 : USRSEL (Register Select) 1=UCSRC 0=UBRRH
' bei UX2=1 und 16MHz Takt
' H L delta H L delta
' 1k2 1666 6 130 0,0% 38k4 51 0 51 +0,2%
' 2k4 832 3 64 0,0% 57k6 34 0 34 -0,8%
' 4k8 416 1 160 -0,1% 115k2 16 0 16 +2,1%
' 9k6 207 0 207 +0,2% 230k4 8 0 8 -3,5%
' 19k2 103 0 103 +0,2% 250k0 7 0 7 0,0%
C = 16 ' fuer Ausgabe auf LCD
Ubrr = C

' UCSRA - USART Control and Status Register A
' * Bit 0 : MPCM Multi-processor Communication Mode
' * Bit 1 : U2X Double the USART transmission speed
' * Bit 2 : UPE Parity Error
' * Bit 2 : PE = UPE For compatibility
' * Bit 3 : DOR Data overRun
' * Bit 4 : FE Framing Error
' * Bit 5 : UDRE USART Data Register Empty
' * Bit 6 : TXC USART Transmitt Complete <===
' * Bit 7 : RXC USART Receive Complete <===
' 0b00000010 ; U2X=1
Ucsra = &B0000_0010

' UCSRC - USART Control and Status Register C
' * Bit 0 : UCPOL Clock Polarity
' * Bit 1 : UCSZ0 Character Size Bit 0
' * Bit 2 : UCSZ1 Character Size Bit 1
' * Bit 3 : USBS Stop Bit Select 0 = 1Stop-Bit , 1 = 2 Stop-Bits
' * Bit 4 : UPM0 Parity Mode Bit 0
' * Bit 5 : UPM1 Parity Mode Bit 1
' * Bit 6 : UMSEL USART Mode Select Async=0 Sync=1
' * Bit 7 : URSEL Register Select
'
' UPM 00 Disabled UCSZ 000 5-Bit , 100 Reserved
' 01 Reserved 001 6-Bit , 101 Reserved
' 10 Even Parity 010 7-Bit , 110 Reserved
' 11 Odd Parity 011 8-Bit , 111 9-Bit
'
' SyncMode TxD Changed RxD Sampled
' UCPOL 0 Rising XCK Edge Falling XCK Edge
' 1 Falling XCK Edge Rising XCK Edge
' 0b10000110 ; URSEL=1 (UCSRC) , USBS=0 UCSZ=3 => Frame-Format 8Bit/1Stop
Ucsrc = &B10000110

' UCSRB - USART Control and Status Register B
' * Bit 0 : TXB8 Transmit Data Bit 8
' * Bit 1 : RXB8 Receive Data Bit 8
' * Bit 2 : UCSZ2 Character Size Bit 2
' * Bit 2 : CHR9 = UCSZ2 For compatibility
' * Bit 3 : TXEN Transmitter Enable
' * Bit 4 : RXEN Receiver Enable
' * Bit 5 : UDRIE USART Data register Empty Interrupt Enable
' * Bit 6 : TXCIE TX Complete Interrupt Enable <===
' * Bit 7 : RXCIE RX Complete Interrupt Enable <===
' r18,0b00011000 ; UCSZ2=0 (8Bit) , TXEN + RXEN => Enable Receiver/Transmitter
Ucsrb = &B00011000


Locate 1 , 1
Lcd "Moins UBRR : " ; C

' #############################################################################
' ##### Hauptschleife #########################################################
' #############################################################################

Do

' Wir bauen uns eine Echo-Routine
A = Ucsra.7 ' Test if Bit 7 is Set : RXC USART Receive Complete
If A <> 0 Then ' Empfang abgeschlossen
D = Udr ' empfangenes Byte aus UDR-Register laden
Bitwait Ucsra.5 , Set ' Wait until Bit 5 is Set : UDRE USART Data Register Empty
Udr = D
End If

Loop


' #############################################################################
' ##### Interrupt-Service-Routinen ############################################
' #############################################################################



' #############################################################################
' ##### Subroutinen ###########################################################
' #############################################################################



End

' #############################################################################
' ##### Programmende ##########################################################
' #############################################################################


Jetzt mach ich erst mal Schluß mit programmieren. Für heute ist es spät
genug. Da will ich mit Interrupts auf dem UART nicht mehr anfangen. Bei
den Tests hatte ich außerdem die BASCOM-Referenz immer als PDF offen
um die passenden Befehle zu finden damit ich das umsetzen kann was ich
grade brauche. Auf die Weise hab ich jetzt den BITWAIT und die Abfrage
von einzelnen Bits in Funktionsregistern mitbekommen. Es gibt keinen
richtigen Bit-Test Befehl unter BASCOM. Naja ... morgen gehts weiter ...
Und wieder was gelernt ;)

Ach ja ... mir ist noch folgendes aufgefallen ... Wenn man ne LCD-Ausgabe
in die Hauptschleife baut dann bricht die Geschwindigkeit ganz massiv
zusammen. Es gab keinen Unterschied zwischen ob ich den 10ms-Wait
drinhatte oder nicht wie die Debug-Ausgaben noch auf dem LCD angezeigt
wurden. Also als Tip ... Die Routinen auf Geschwindigkeit bringen und
wirklich nur dann aufdas LCD ausgeben wenn es unbedingt sein muß sonst
kann man den Atmel auch gleich mit 500kHz laufen lassen :D

Gruß
Dino
 
Hallo Grandpa Michael ;) ,

ja ich weiß, mit den "krummen" Quarzen. Wenn man sich die Formel zur Berechung von UBRR ansieht, gibt's im Prinzip 2 Möglichkeiten, sich "fehlerfreie" Baudraten auszusuchen: entweder durch 2, 4, 8, 16 (Zweierrreihe) teilbar oder durch 5, 10, 20 (Fünferreihe).

Ich habe ja auch nicht alle Baudraten probiert, nur die Standardwerte mit sehr kleiner Abweichung (so 0,3%) und aus der Fünferreihe, mit 0% Abweichung. Die hab' ich zusätzlich PC-seitig mit dem Nullmodemstecker geprüft, um hier nicht einem anderen Fehler aufzusitzen.
Danke für den Hinweis.


@Dino

ich bin erst einmal geplättet, was du dir für eine Arbeit machst. Da wird sicher unter dem Strich was rauskommen - bin schon gespannt.


LG
Werner :flowers:
 
Hi Werner,

Ich habe ja auch nicht alle Baudraten probiert, nur die Standardwerte mit sehr kleiner Abweichung (so 0,3%) und aus der Fünferreihe, mit 0% Abweichung. Die hab' ich zusätzlich PC-seitig mit dem Nullmodemstecker geprüft, um hier nicht einem anderen Fehler aufzusitzen.
wie bereits geschrieben liegt bei mir der Fehler bei den 115k2 bei +2,1% !
Also mach dir da keinen Kopf wegen 0,0% oder 0,3% :D


@Dino

ich bin erst einmal geplättet, was du dir für eine Arbeit machst. Da wird sicher unter dem Strich was rauskommen - bin schon gespannt.
Also ...
1. Dadurch weiß ich jetzt selber wieder mehr da ich das noch nicht unter
Bascom gemacht habe :p
2. Das hoffe ich doch mal das da was bei rauskommt :D

Aber irgendwie wird das ganze Zeugs bei 115k2 8n1 und +2,1% Fehler
schon recht zickig mit der Synchronisation auf den Datentakt :eek: :rolleyes:
Es ist ja auch nur ein Stopbit da um den Taktfehler bei der Datenrate wieder
aufzufangen. Außerdem sind 115k2 schon ne Menge Holz die die Puffer vom
Terminalprogramm und das Proggi im Atmel bei vollem Datenstrom ohne Pause
erst mal mitmachen müssen :cool: Und das natürlich ohne Handshaking !

Gruß
Dino
 
Hi dino,

nochmals danke :flowers: .

Ich verfolge gerade eine Spur, dass es am USB-seriell Wandler liegen könnte. Die ganze Zeit benutzte ich einen mit einem Prolific-Chip und habe jetzt einen mit FTDI-Chipsatz.
Der FTDI geht schon einmal ohne Interrupt bei 50 kBaud, also oberhalb der 38,4k-Grenze, die der Prolific standhaft verweigert hat (obwohl beide nominal bis über 1MBit gehen sollen !!).
Ich werd' da noch weiter "forschen" und über die Ergebnisse berichten.

Bis demnächst
Werner
 
Hi Werner,

Ich verfolge gerade eine Spur, dass es am USB-seriell Wandler liegen könnte. Die ganze Zeit benutzte ich einen mit einem Prolific-Chip und habe jetzt einen mit FTDI-Chipsatz.
Der FTDI geht schon einmal ohne Interrupt bei 50 kBaud, also oberhalb der 38,4k-Grenze, die der Prolific standhaft verweigert hat (obwohl beide nominal bis über 1MBit gehen sollen !!).
Ich werd' da noch weiter "forschen" und über die Ergebnisse berichten.
10a_USB-Dongle.gif
Meinst du so einen Chip ?
Mit dem hab ich es bei mir getestet :D

Gruß
Dino
 
Sodele,

den ersten Fehler, das scheinbare Baudratenlimit von 38,4 kBaud, habe ich gefunden. Es lag tatsächlich am Prolific-USB/seriell Wandler. Der schafft scheinbar die TTL-Pegel des ATMega (über den MAX232) bei höheren Baudraten nicht mehr. Das würde auch erklären, dass er mit dem TxD/RxD Stecker trotzdem funktioniert hat, da er dann ja die Triggerschwellen des Wandlers und nicht dews ATMega relevant sind.

Der FTDI scheint über eine niedigere Ausgangsimpedanz zu verfügen und/oder damit kräftigere/höhere Pegel zu bringen.

Wie dem auch sei, mit dem FTDI hab' ich's bis 200kBaud über das unten stehende Programm getestet (im Interrupt).

Code:
[FONT="Fixedsys"][SIZE="2"]
Const QuarzFrequenz = 16000000
Const BaudRate      = 200000
Const MinUBRR       = (QuarzFrequenz\16\Baudrate)-1 ' UBRR -Wert für 4800 Baud
$regfile = "m16def.dat"
$crystal = QuarzFrequenz
'------------------------------------------------------------------------------
On Urxc Rs232receive Nosave      ' Keine automatische Register-Rettung
'Enable Urxc                      ' Interrupt (Byte über USART erhalten) enabled
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
Const Cbuffsize = 20                    ' Maximale Anzahl-1 der Stringzeichen
Const Skipchar = 10                     ' LineFeed       (ignorieren)
Const Terminator = 13                   ' CarriageReturn (Stringende)
Const Rs232datapresent = &B10000000     ' Bit 7 (Maske für Registeroperationen)
Const Rs232databranch = 7               ' Bit 7 für Branch (SBRS/SBRC)
Mreg  Alias R16
Zreg  Alias R17
Freg  Alias R18
'z2reg Alias R18
'------------------------------------------------------------------------------
Dim Rsbuffcount As Byte
Dim RSError     As Byte
Dim Rsbuffer(cbuffsize) As Byte                      ' von 1..CBuffSize Zeichen
Dim Rsbuffstring As String*Cbuffsize At Rsbuffer Overlay
Dim Flagreg As Byte                                  ' Speicher für 8 Flags

Dim I As Byte
'******************************************************************************
'***************************** HAUPTPROGRAMM **********************************
'******************************************************************************
Flagreg     = 0                   ' alle Flags zurücksetzen
Rsbuffcount = 0               ' Zeichenzähler zurücksetzen
RSError     = "?"

GOSUB _INIT_USART             ' USART initialisieren
Enable Interrupts             ' Interrupts global zulassen

Do
$asm
Mainwait0:                    ' Auf kompletten String von RS232 (vom PC) warten
 lds   fReg,{FlagReg}         ' dazu FlagReg auf Bit 7 prüfen
 SBRS  fReg,RS232DataBranch   ' Sprung, falls Bit 7 gesetzt ist
 rjmp  MainWait0              ' sonst weiter warten

 RCALL Analysiere

 lds   fReg,{FlagReg}         ' FlagReg Bit 7
 CBR   fReg,RS232DataPresent  ' (CBR: Clear Bit in Register)
 sts   {FlagReg},fReg         ' löschen
$end Asm
Loop
End
'******************************************************************************
'********************* RS232- Interrupthandler (Receiver) *********************
'******************************************************************************
Rs232receive:
$asm
  push  mReg                  ' 1.Arbeitsregister retten
  IN    mReg,SREG             ' Statusregister einlesen
  push  mReg                  ' und sichern
  push  zReg                  ' 2.Arbeitsregister retten
  PUSH  fReg                  ' eigenes Flagregister retten
'..............................................................................
  IN    mReg,UDR              ' Zeichen von COM-Schnittstelle einlesen
  cpi   mReg,SkipChar         ' falls zu überlesen, dann fertig
  breq  RS232Receive4         ' -> Sprung zum Ende
  lds   fReg,{FlagReg}        ' Flagregister lesen (nach fReg)
  SBRC  fReg,RS232DataBranch  ' Sprung, falls das RS232Data Bit gelöscht
  RJMP  RS232Receive4         ' sonst beenden (gesendetes Byte geht verloren)
'------------------------------------------------------------------------------
  lds   zReg,{RSBuffCount}    ' Zeichenzähler aus RAM lesen (nach zReg)
  push  YL                    ' Y-Pointer auf den Datenpuffer setzen
  push  YH
'  ldi  YL,low(RSBuffer)      ' Tabellenoffset im Datensegment
'  ldi  YH,high(RSBuffer)     ' .. so will's der Assembler
  Loadadr Rsbuffer(1) , Y     ' .. so will's BASCOM
'  LOADADR RSBuffString,Y     ' .. oder auch so
  add   YL,zReg               ' Zeichenzähler um eins erhöhen
  brcc  RS232Receive0         ' und zum Y-Pointer addieren
  inc   YH
Rs232receive0:
  cpi   mReg,Terminator       ' (LineFeed #10): Endekennzeichen
  brne  RS232Receive2
Rs232receive1:
  clr   mReg                  ' Zeichen = #10, dann #0 eintragen UND
  CLR   zReg                  ' Zeichenzähler ebenfalls auf #0
  SBR   fReg,RS232DataPresent ' Bit 7: Flag für Daten vollständig setzen
  sts   {FlagReg},fReg        '        im Flagregister setzen
  rjmp  RS232Receive3         '        MIT MASKE $80 !!!!
Rs232receive2:
  inc   zReg                  ' Anzahl gelesener Zeichen erhöhen
  cpi   zReg,CBuffsize        ' Puffer schon voll
  brsh  RS232Receive1         ' Sprung, falls ja (dann als #10 behandeln)
Rs232receive3:
  st    Y,mReg                ' Zeichen in Puffer eintragen
  sts   {RSBuffCount},zReg    ' Counter oder (#0 OR RS232Data) eintragen
  pop   YH
  pop   YL
'..............................................................................
Rs232receive4:                ' Lead-Out
  POP   fReg
  pop   zReg                  ' benutzte Register restaurieren
  pop   mReg                  ' sowiw flags wiederherstellen
  Out Sreg , Mreg
  pop   mReg
' RETI                        ' BASCOM ersetzt in diesem Fall, d.h. ISR-Routine
$end Asm                      ' die über ON 'Interrupt' 'Label' deklariert ist
Return                        ' dieses 'RETURN' durch 'RETI' (nicht RET)
'..............................................................................
'..............................................................................
'..............................................................................
$ASM
_INIT_USART:
  LDI  zReg,MinUBRR\255   ' lädt das Highbyte
  LDI  mReg,MinUBRR       ' lädt daS Lowbyte der Baudrate
'..............................................................................
_SET_Baudrate:
  OUT  UBRRH,zReg
  OUT  UBRRL,mReg
'..............................................................................
  LDI  mReg,&B00011000        ' Setzen von RXEN,TXEN =1  &  UCSZ2=0
  OUT  UCSRB,mReg
  SBI  UCSRB,RXCIE            ' Setzen von RXCIE,
  RET
$END ASM
'==============================================================================
'====================== String nach Byte/Word Routinen ========================
'==============================================================================
CharUpper:                    ' wandelt Kleinbuchstaben in Großbuchstaben
$ASM
     cpi    mReg,asc("z")+1
     BRSH   CharUpperE        ' Sprung bei größer oder gleich
     CPI    mReg,asc("a")
     BRLO   CharUpperE        ' Sprung kleiner
     SUBI   mReg,&H20
CharUpperE:
     ret
'------------------------------------------------------------------------------
HexCharToNibble_X:
     LD     mReg,X+
HexCharToNibble:
     RCall  CharUpper
     CPI    mReg,asc("A")
     BRLO   HexCharToNibble01
     CPI    mReg,asc("G")
     BRSH   HexCharToNibbleErr
     subi   mReg,55
HexCharToNibbleOK:
     clc
     ret
HexCharToNibble01:
     Subi   mReg,asc("0")
     cpi    mReg,10
     BRLO   HexCharToNibbleOK
HexCharToNibbleErr:
     clr    mReg
     sec
     ret
'------------------------------------------------------------------------------
WordFrom4Char_X:                ' ** 4 (String-)Zeichen in hexadezimaler Form
     RCALL  ByteFrom2Char_X     ' ** nach WORD-Variable wandeln
     MOV    zReg,mReg           ' E: Stringzeiger in X
ByteFrom2Char_X:                ' A: LOW in mReg, High in zReg
     ld     mReg,X+             ' ** 2 (String-)Zeichen in hexadezimaler Form
     rcall  HexCharToNibble     ' ** nach Byte-Variable wandeln
     brcs   ByteFrom2Char_Xe2   ' E: Stringzeiger in X
     SWAP   mReg                ' A: LOW in mReg
     push   zReg                ' Geänderte Register: X steht hinter letztem
     mov    zReg,mReg           ' gelesenen Zeichen
     ld     mReg,X+             ' geändert : mReg bzw. mReg & zReg
     rcall  HexCharToNibble
     brcs   ByteFrom2Char_Xe1
     add    mReg,zReg
ByteFrom2Char_Xe1:
     pop    zReg
ByteFrom2Char_Xe2:
     ret
'..............................................................................
WordFromString:                 ' 4 Zeichen von X^ lesen, nach Word wandeln
     RCALL WordFrom4Char_X      ' und nach Y^ eintragen
     ST    Y+,mReg
     ST    Y+,zReg
     RET
'------------------------------------------------------------------------------
'---------------------- Byte/Word nach String-Routinen ------------------------
'------------------------------------------------------------------------------
BytetoHex_INT:
     andi   mReg,$0F
     Cpi    mReg,10
     brsh   ByteToHex_Y0
     ori    mReg,$30          '"0" addieren
     ret
Bytetohex_y0:
     Subi   mReg,9            ' -10 + 1 => A Nach #1
     ori    mReg,$40          ' oder '@' ist gleich 'A'-1
     ret
'------------------------------------------------------------------------------
ByteToHexChar_Y:
     PUSH   mReg
     SWAP   mReg           ' High Nibble Zuerst
     RCALL  ByteToHex_INT
     ST     Y+,mReg
     POP    mReg
NibbleToHexChar_Y:
     RCALL  ByteToHex_INT
     ST     Y+,mReg
     RET
'------------------------------------------------------------------------------
'------------------- Zeichen bzw. Stringausgabe -------------------------------
'------------------------------------------------------------------------------
sendstring:              '
  PUSH  XL
  PUSH  XH
sendstring0:
  LD    mReg,X+
  CPI   mReg,0
  BREQ  sendstringE
  RCALL sendchar
  RJMP  sendstring0
sendstringE:
  POP   XH
  POP   XL
  RET
'------------------------------------------------------------------------------
SendRSBuffstring:
  Loadadr RSBuffstring,X
SendString_X:
  rcall sendstring
SendCRLF:
  ldi   mReg,13
'  rcall sendchar
'  ldi   mReg,10
;..............................................................................
sendchar:
  sbis  UCSRA,UDRIE           ' Warten bis UDR für das nächste
  rjmp  sendChar              ' Byte bereit ist
  out   UDR,mReg
  ret
$end Asm
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
$ASM
Value_mReg_To_Y:                 ' Liest 2 Hex-Zeichen aus dem IN-Puffer (Y)
  PUSH    mReg
  LDI     mReg,ASC("$")
  ST      Y+,mReg
  pop     mReg
  RCALL   ByteToHexChar_Y        ' und wandelt nach Byte (in mReg)
  LDI     mReg,ASC(",")
  ST      Y+,mReg
  RET
'...............................................................................
USARTStatus:
  LoadAdr RSBuffer(2),Y
USARTStatus1:
  IN      mReg,UBRRL             ' UBRRL
  RCALL   Value_mReg_To_Y

  CLI
  IN      mReg,UBRRH
  IN      mReg,UCSRC             ' UCRSC
  SEI
  RCALL   Value_mReg_To_Y

  IN      mReg,UCSRB             ' UCRSB
  RCALL   Value_mReg_To_Y

  IN      mReg,UCSRA             ' UCRSA
  RCALL   Value_mReg_To_Y        ' ByteToHexChar_Y
  clr     mReg
  ST      -Y,mReg                ' Komma mit #0 überschreiben
  RET
$END ASM
'------------------------------------------------------------------------------
Dim ii as word, Ptr as Word, TestVar as word

Analysiere:
 Select case RSBuffer(1)
  case "X" : LoadAdr RSBuffer(2),X
             LoadAdr TestVar,Y
             RCALL   WORDFromString
             LD      mReg,X+                      ' 1 Zeichen überlesen
             Loadadr Ptr,Y
             ST      Y+,XL
             ST      Y+,XH
             for ii=0 to TestVar       '###################################
              Loadadr Ptr,Y            ' diese Mischung von Assembler und
              LD      XL,Y+            ' BASCOM (in einer for..next Schleife)
              LD      XH,Y+            ' ist grenzwertig und nicht gerade
              RCALL   SendString_X     ' empfehlenswert (aber funktioniert)
             Next ii                   '###################################
 case "B"  : LoadAdr RSBuffer(2),X
             RCALL   WordFrom4Char_X

             RCALL   _Set_BaudRate

             LoadAdr RSBuffer(2),Y
             push    mReg
             mov     mReg,zReg
             RCALL   ByteToHexChar_Y
             POP     mReg
             RCALL   ByteToHexChar_Y
             clr     mReg
             st      Y+,mReg
             RCALL   SendRSBuffString


 case "Y"  : RCALL   SendRSBuffString

 case "S"  : RCALL   USARTStatus
             RCALL   SendRSBuffString

 case else : LoadAdr RSError,X
             RCALL   SendString_X
 End Select
RETURN
[/SIZE][/FONT]

Ich habe (nach anderen Tests) für einen Benchmarktest den String "X4E1F,123456789" vom PC an den Mega 16 geschickt. Aus dem ersten Teil des strings (bis zum Komma) wird von dem Testprogramm im AVR das Kommando "X" extrahiert (siehe im Listing "Analysiere"). Danach werden die nächsten 4 Zeichen als hexadezimale Form einer 16-Bit Zahl interpretiert (siehe die Routinen), d.h. 4E1F = 19999 und in den Binärcode konvertiert.

Das Komma dient als Trennzeichen (wird noch nicht ausgewertet) und der Teil nach dem Komma als String zurückgeschickt - und zwar 20000 mal, wobei noch ein Carriage Return angehängt wird. Auf dem PC wird jeder zurückgeschickte String überprüft und die Zeit für die 20000 Strings gemessen. Es waren in 5 Durchläufen so 10,020 Sekunden im Schnitt, wobei alle Strings korrekt waren.

Jetzt ergibt sich folgende Rechnung: Der String "123456789" hat 9 Zeichen, mit Carriage Return sind das also 10 Zeichen. Bei 8N1 ergibt das 100 Bit pro String. 20000 Strings sind also 2 Millionen Bit; Bei einer Baudrate von 200kBaud sollte das dann 10 Sekunden dauern. :p Passt also ziemlich gut :pleasantry: .

So, damit ist das Baudratenproblem gelöst. Warum die Umschaltung nicht geht, kommt jetzt dran. Eventuell ist im Prolific-Treiber ein Bug, nämlich dass die Baudrate eventuell an den eigenen Chip angepasst wird und man auf die von der Systemsteuerung vorgegebenen benutzen müßte.
Ist aber noch Spekulation. Der FTDI läßt auf jeden Fall eigene Baudraten zu - 200kBaud sind kein Standard, aber gehen (s.o.).


Bis bald
Werner
 
Sodele :) ,

Die Umschaltung der Baudrate ist auch im Kasten. Die bisherige "Unwilligkeit" war eine Kombination aus 2 "Fehlern".

1.) Die COM-Schnittstelle muss vor setzen der neuen Baudrate geschlossen werden (und mit der neuen geöffnet).
2.) VORHER muss die neue Baudrate (bzw. der neue UBRR-Wert) dem AVR mitgeteilt werden und eine Initialisierungszeit abgewartet werden.

Ich habe daher die Initialisierung bzw. das Setzen der Baudrate neu codiert.

Code:
[FONT="Fixedsys"]$ASM
_SET_Baudrate:
  CBI    UCSRB,RXCIE          ' Löschen von RXCIE => COM-Interrupt verhindern
  RCALL  _SET_Baudrate1       ' Baudrate setzen
[COLOR="Red"]  PUSH   XL                   ' Zeit abwarten
  PUSH   XH
  CLR    XL
  CLR    XH
_SET_Baudrate0:
  SBIW   XL,1
  BRNE   _SET_Baudrate0
  POP    XH
  POP    XL[/COLOR]
  SBI    UCSRB,RXCIE          ' Setzen von RXCIE,
  RET
'..............................................................................
_INIT_USART:
  LDI  zReg,MinUBRR\255   ' lädt das Highbyte
  LDI  mReg,MinUBRR       ' lädt daS Lowbyte der Baudrate
'..............................................................................
_SET_Baudrate1:
  OUT  UBRRH,zReg
  OUT  UBRRL,mReg
'..............................................................................
  LDI  mReg,&B00011000        ' Setzen von RXEN,TXEN =1  &  UCSZ2=0
  OUT  UCSRB,mReg
[COLOR="Red"]'  SBI  UCSRB,RXCIE            ' Setzen von RXCIE,[/COLOR]  RET
$END ASM[/FONT]

Die Routine "_INIT_USART" wird während der Initialisierung/Reset aufgerufen, wobei das RXCIE-Flag noch von Hand in der Initialisierung gesetzt werden muss (siehe roten, auskommentierten Teil).

Im laufenden Programm kann dann über die Routine "_SET_Baudrate" der neue UBRR-Wert gesetzt werden (im Registerpaar R16/R17).


Uff ;)
Werner
 
Hi Dino :) ,

einen Hinweis auf die Warteschleife für die Baudratenumschaltung hab' ich im Internet gefunden : http://www.avr-asm-tutorial.net/akkuload/de/akkuuart.asm
War eine ziemliche Rumsucherei :rolleyes:. Das Internet ist ja bekanntlich ein riesiger Misthaufen :D mit ein paar Perlen drin (die es zu finden gilt):).

Das mit dem Prolific-Chip, dass er bei dir ging, hab' ich eben erst von dir gelesen. Ich hab' insgesamt 4 ausprobiert, 2 gleiche (von Pollin) und 2 andere. Waren aber alle "NUR" USB 1.1. Ob's damit zusammenhängt, was aber "eigentlich" nicht sein sollte. Vielleicht sind die älteren Modelle doch etwas kritischer in den elektrischen Daten (höhere Ausgangsimpedanz) ??


Nochmals danke für dein Engagement
Werner :)
 
Moin!

Da Ihr beiden Euch ja ganz gut mit dem UART auszukennen scheint, anbei mal mein Code zur Ansteuerung meiner LED-Displays. Das Problem ist, dass ich die Displays so schnell wie möglich per RS232 füttern möchte, aber leider schon bei 57.600 bps Schluss ist. Auf PC-Seite kommt ein FDTI-Wandler (UM232H) zum Einsatz, den ich direkt über die API aus .NET anspreche. Das habe ich erstmal nur bis 921.600 bps getestet, was einwandfrei funktioniert hat. Ich schließe daher die PC-Seite aus.

Wäre nett, wenn Ihr Euch den Code mal ansehen könnt. Vielleicht gibts da ja noch Möglichkeiten, das zu optimieren. Gern auch in ASM...verstehe ich zwar nicht, würd' das aber gern mal austesten.

Danke und Gruß
Jan

Code:
$regfile = "m644def.DAT" 
$crystal = 22118400 
$hwstack = 128 
$swstack = 128 
$framesize = 128 
$baud = 57600 

Ddrb = &B11111111 

strobe Alias Portb.1 

Config Serialin = Buffered , Size = 255 

Config Spi = Hard , Interrupt = Off , Data Order = msb , Master = Yes , Polarity = high , Phase = 1 , Clockrate = 4 , Noss = 1 , Spiin = 0 

Spiinit 
'Reset Spcr.spr1 : Reset Spcr.spr0 : Set Spsr.spi2x 

On Timer1 Mux 
Config Timer1 = Timer , Prescale = 1 
Enable Timer1 

Enable Interrupts 

Const physicalDisplayHeight = 32 
Const physicalDisplayWidth = 256 
Const overallPixelCount = physicalDisplayWidth * physicalDisplayHeight 
Const ledBufferSize = overallPixelCount / 8 
Const numberOfModulesPerRow = physicalDisplayWidth / 8 

Dim ledBufferRed(ledBufferSize) As Byte 
Dim ledBufferGreen(ledBufferSize) As Byte 

'Used in timer-isr... 
Dim currentRow As Byte 
Dim startIndex As Integer 

Dim x as Integer 
'Fill buffer cause display's inverted (0 = LED ON, 1 = LED OFF) 
For x = 1 To ledBufferSize 
    ledBufferRed(x) = &HFF 
    ledBufferGreen(x) = &HFF 
Next 

Dim serialInput As Word 
Dim arrayIndexInput As Word 
Dim bitIndexInput As Word 
Dim colorInput As Word 
Dim arrayIndex As Integer 
Dim color As Byte 
Dim bitIndex As Byte 

Do 

  serialInput = IsCharWaiting() 

  If serialInput = 1 Then 

     Inputbin serialInput 

     arrayIndexInput = serialInput and &b0000011111111111 
     bitIndexInput = serialInput and &b0011100000000000 
     colorInput = serialInput and &b1100000000000000 

     Shift bitIndexInput , Right , 11 
     Shift colorInput , Right , 14 

     arrayIndex = arrayIndexInput 
     color = colorInput 
     bitIndex = bitIndexInput 

     Select Case color 
            Case 0 
               ledBufferRed(arrayIndex).bitIndex = 1 
               ledBufferGreen(arrayIndex).bitIndex = 1 
            Case 1 
               ledBufferRed(arrayIndex).bitIndex = 0 
               ledBufferGreen(arrayIndex).bitIndex = 1 
            Case 2 
               ledBufferRed(arrayIndex).bitIndex = 1 
               ledBufferGreen(arrayIndex).bitIndex = 0 
            Case 3 
               ledBufferRed(arrayIndex).bitIndex = 0 
               ledBufferGreen(arrayIndex).bitIndex = 0 
     End Select 

  End If 

Loop 

Mux: 
   timer1 = 39000 

   If currentRow = 16 Then currentRow = 0 

   startIndex = currentrow * numberOfModulesPerRow 
   Incr startIndex 

   Spiout ledBufferGreen(startIndex + 512) , numberOfModulesPerRow 
   Spiout ledBufferRed(startIndex + 512) , numberOfModulesPerRow 
   Spiout ledBufferGreen(startIndex) , numberOfModulesPerRow 
   Spiout ledBufferRed(startIndex) , numberOfModulesPerRow 

   Spiout currentRow , 1 

   Set strobe                                               'Latch data to output 
   Reset strobe 

   Incr currentRow 

Return
 
Hallo Jan,

Das Problem ist, dass ich die Displays so schnell wie möglich per RS232 füttern möchte, aber leider schon bei 57.600 bps Schluss ist. Auf PC-Seite kommt ein FDTI-Wandler (UM232H) zum Einsatz, den ich direkt über die API aus .NET anspreche. Das habe ich erstmal nur bis 921.600 bps getestet, was einwandfrei funktioniert hat. Ich schließe daher die PC-Seite aus.

Code:
$regfile = "m644def.DAT" 
$crystal = 22118400 
$hwstack = 128 
$swstack = 128 
$framesize = 128 
$baud = 57600
Du hast also einen Mega644 mit 22,1184MHz Quarz laufen. Da sehen dann die möglichen Baudraten folgendermaßen aus ...

Du solltest eigentlich bis 230400Baud ohne Fehler übertragen können. Danach wird es enger weil die Werte im Baudratengenerator nicht mehr jeden x-beliebigen Teilerfaktor zulassen. Für höhere Werte würde ich das Steuerbit U2X auf 1 setzen um mehr Basistakt zu haben. Dann sind mit 0/5 und mit 0/2 nur noch 460800 und 921600 möglich. Bei 0/1 im UBBRH/UBBRL bist du bei 1,3824MBit/s. Das ist allerdings schon recht grenzwertig.

Meine PCI-HiSpeed-UART-Karte werde ich wohl in den nächsten Wochen einbauen und dann mal sehen was rauszuholen ist ... Mal wieder Atmels übertakten ;)

Also ich tippe mal das es bei dir eher an der Einstellung des Teilerfaktors liegt. Das da zuviel Abweichung ins Spiel kommt und die Kommunikation dabei zusammenbricht. Stell die Werte in UBBRH/UBBRL und das U2X-Bit doch einfach per Hand um rauszubekommen was da schief läuft. Evtl kommt bei den hohen Taktraten auf dem UART aber auch Bascom mit seinen FIFO-Buffern nicht mehr mit der restlichen Zeit aus und verschluckt sich einfach ...

Gruß
Dino
 
Hallo Jan,

ich kenn' mich in Bascom noch nicht so sehr aus - meine (Vor-)Liebe ist Assembler.
Eine zeitkritische Routine in einer Hochsprache zu programmieren ist ohne entsprechende Erfahrung ein ziemliches Glücksspiel. Ich hab' auch schon gelesen, dass Bascom nicht gerade den schnellsten Code generiert.

Wenn ich deinen Code richtig verstanden habe, empfängst du ein einzelnes binäres Byte und wertest es aus. In dem Fall könnten wir die Originalroutine (Assembler) von diesem Thread so abwandeln, dass sie das Zeichen empfängt und dir sogar "sagt", wenn die Zeichen zu schnell kommen. Du könntest dann die passende Baudrate einstellen, bis es passt.


Grüße
Werner
 
Hi Dino, hi Werner!

Ich denke, es könnte auch am Timer liegen, da bleibt einfach zu wenig Zeit für den UART?! Ich habe mal versucht, etwas aus der Timer-Routine in die Hauptschleife zu verlagern. Werden den Code gleich posten, wenn ich ihn gesäubert habe. Damit geht auch 115.200 bps. Wäre aber schön, wenn mehr ginge :)

@Werner: Ich empfange 2 Bytes, also ein Word, was ich dann zerlege. Ggf. kann man da noch einiges besser machen, wenn man das in ASM macht. Kannst Du mir da behilflich sein (anders ausgedrückt: Kannst Du mir das umschreiben ;)) Ebenso bringt es sicher was, Deine Routine etwas anzupassen, dann kann ich mich da langsam an die max. Geschwindigkeit rantasten.

Danke und Gruß
Jan
 
Hier nun der Code, der mit 115.200 bps läuft.

Habe Teile der Timer-Routine in die Hautpschleife ausgelagert.

Code:
$regfile = "m1284pdef.DAT"
$crystal = 22118400
$hwstack = 128
$swstack = 128
$framesize = 128
$baud = 115200

Ddrb = &B11111111

strobe Alias Portb.1

Declare Sub ClearMatrix

Config Serialin = Buffered , Size = 255

Config Spi = Hard , Interrupt = Off , Data Order = msb , Master = Yes , Polarity = high , Phase = 1 , Clockrate = 4 , Noss = 1 , Spiin = 0

Spiinit
'Reset Spcr.spr1 : Reset Spcr.spr0 : Set Spsr.spi2x

On Timer1 Mux
Config Timer1 = Timer , Prescale = 1
Enable Timer1

Enable Interrupts

Const physicalDisplayHeight = 32
Const physicalDisplayWidth = 256
Const overallPixelCount = physicalDisplayWidth * physicalDisplayHeight
Const ledBufferSize = overallPixelCount / 8
Const numberOfModulesPerRow = physicalDisplayWidth / 8
Const highDisplayIndex = ledBufferSize / 2

Dim ledBufferRed(ledBufferSize) As Byte
Dim ledBufferGreen(ledBufferSize) As Byte

'Used in timer-isr...
Dim currentRow As Byte
Dim startIndex As Integer

Dim x as Integer
'Fill buffer cause display's inverted (0 = LED ON, 1 = LED OFF)
For x = 1 To ledBufferSize
    ledBufferRed(x) = &HFF
    ledBufferGreen(x) = &HFF
Next

Dim serialInput As Word
Dim arrayIndexInput As Word
Dim bitIndexInput As Word
Dim colorInput As Word
Dim arrayIndex As Integer
Dim color As Byte
Dim bitIndex As Byte

Dim STAT_ISR As Byte 
Dim startIndex_highDisplayIndex As Integer

Do
   If currentRow = 16 Then currentRow = 0
   startIndex = currentRow * numberOfModulesPerRow
   startIndex_highDisplayIndex = startIndex + highDisplayIndex

  serialInput = IsCharWaiting()

  If serialInput = 1 Then

     Inputbin serialInput

     'clear serialin

     arrayIndexInput = serialInput and &b0000011111111111
     bitIndexInput = serialInput and &b0011100000000000
     colorInput = serialInput and &b1100000000000000

     Shift bitIndexInput , Right , 11
     Shift colorInput , Right , 14                          '
                      '
     arrayIndex = arrayIndexInput
     color = colorInput
     bitIndex = bitIndexInput

     If arrayIndex = 0 Then

        For x = 1 To ledBufferSize
            ledBufferRed(x) = &HFF
            ledBufferGreen(x) = &HFF
        Next
     Else
        Select Case color
               Case 0
                  ledBufferRed(arrayIndex).bitIndex = 1
                  ledBufferGreen(arrayIndex).bitIndex = 1
               Case 1
                  ledBufferRed(arrayIndex).bitIndex = 0
                  ledBufferGreen(arrayIndex).bitIndex = 1
               Case 2
                  ledBufferRed(arrayIndex).bitIndex = 1
                  ledBufferGreen(arrayIndex).bitIndex = 0
               Case 3
                  ledBufferRed(arrayIndex).bitIndex = 0
                  ledBufferGreen(arrayIndex).bitIndex = 0
        End Select
     End If
  End If

Loop

Sub ClearMatrix
        For x = 1 To ledBufferSize
        ledBufferRed(x) = &HFF
        ledBufferGreen(x) = &HFF
        Next
End Sub

Mux:
   Timer1 = 52267

   If STAT_ISR = 0 Then

		Incr startIndex_highDisplayIndex

		Spiout ledBufferGreen(startIndex_highDisplayIndex) , numberOfModulesPerRow
		Spiout ledBufferRed(startIndex_highDisplayIndex) , numberOfModulesPerRow

		Incr STAT_ISR
	Else
		Incr Startindex

		Spiout ledBufferGreen(startIndex) , numberOfModulesPerRow
		Spiout ledBufferRed(startIndex) , numberOfModulesPerRow

		Spiout currentRow , 1

		Set strobe                                               'Latch data to output
		Reset strobe

		Incr currentRow

		Incr STAT_ISR
		IF STAT_ISR > 1 Then STAT_ISR = 0
End If

Return
 
Hallo Jan,

die Routine auf Zweibyte Empfang umstellen - ist nicht so schwer. Ich werd' mal morgen danach schauen. Den Code aus Beitrag #31 hab' ich schon einmal reinkopiert (aber noch nicht geändert).

Grüße
Werner

Code:
'******************************************************************************
'********************* RS232- Interrupthandler (Receiver) *********************
'******************************************************************************
Rs232receive:
$asm
  push  mReg                  ' 1.Arbeitsregister retten
  IN    mReg,SREG             ' Statusregister einlesen
  push  mReg                  ' und sichern
  push  zReg                  ' 2.Arbeitsregister retten
  PUSH  fReg                  ' eigenes Flagregister retten
'..............................................................................
  IN    mReg,UDR              ' Zeichen von COM-Schnittstelle einlesen
  cpi   mReg,SkipChar         ' falls zu überlesen, dann fertig
  breq  RS232Receive4         ' -> Sprung zum Ende
  lds   fReg,{FlagReg}        ' Flagregister lesen (nach fReg)
  SBRC  fReg,RS232DataBranch  ' Sprung, falls das RS232Data Bit gelöscht
  RJMP  RS232Receive4         ' sonst beenden (gesendetes Byte geht verloren)
'------------------------------------------------------------------------------
  lds   zReg,{RSBuffCount}    ' Zeichenzähler aus RAM lesen (nach zReg)
  push  YL                    ' Y-Pointer auf den Datenpuffer setzen
  push  YH
'  ldi  YL,low(RSBuffer)      ' Tabellenoffset im Datensegment
'  ldi  YH,high(RSBuffer)     ' .. so will's der Assembler
  Loadadr Rsbuffer(1) , Y     ' .. so will's BASCOM
'  LOADADR RSBuffString,Y     ' .. oder auch so
  add   YL,zReg               ' Zeichenzähler um eins erhöhen
  brcc  RS232Receive0         ' und zum Y-Pointer addieren
  inc   YH
Rs232receive0:
  cpi   mReg,Terminator       ' (LineFeed #10): Endekennzeichen
  brne  RS232Receive2
Rs232receive1:
  clr   mReg                  ' Zeichen = #10, dann #0 eintragen UND
  CLR   zReg                  ' Zeichenzähler ebenfalls auf #0
  SBR   fReg,RS232DataPresent ' Bit 7: Flag für Daten vollständig setzen
  sts   {FlagReg},fReg        '        im Flagregister setzen
  rjmp  RS232Receive3         '        MIT MASKE $80 !!!!
Rs232receive2:
  inc   zReg                  ' Anzahl gelesener Zeichen erhöhen
  cpi   zReg,CBuffsize        ' Puffer schon voll
  brsh  RS232Receive1         ' Sprung, falls ja (dann als #10 behandeln)
Rs232receive3:
  st    Y,mReg                ' Zeichen in Puffer eintragen
  sts   {RSBuffCount},zReg    ' Counter oder (#0 OR RS232Data) eintragen
  pop   YH
  pop   YL
'..............................................................................
Rs232receive4:                ' Lead-Out
  POP   fReg
  pop   zReg                  ' benutzte Register restaurieren
  pop   mReg                  ' sowiw flags wiederherstellen
  Out Sreg , Mreg
  pop   mReg
' RETI                        ' BASCOM ersetzt in diesem Fall, d.h. ISR-Routine
$end Asm                      ' die über ON 'Interrupt' 'Label' deklariert ist
Return                        ' dieses 'RETURN' durch 'RETI' (nicht RET)
'..............................................................................
'..............................................................................
'..............................................................................

Überarbeitung (noch nicht fertig!)

Code:
'******************************************************************************
'********************* RS232- Interrupthandler (Receiver) *********************
'******************************************************************************
Rs232receive:
$asm
  push  mReg                  ' 1.Arbeitsregister retten
  IN    mReg,SREG             ' Statusregister einlesen
  push  mReg                  ' und sichern
  push  zReg                  ' 2.Arbeitsregister retten
  PUSH  fReg                  ' eigenes Flagregister retten
'..............................................................................
  IN    mReg,UDR              ' Zeichen von COM-Schnittstelle einlesen
[COLOR="#FF0000"]'  cpi   mReg,SkipChar         ' falls zu überlesen, dann fertig
'  breq  RS232Receive4         ' -> Sprung zum Ende[/COLOR]
  lds   fReg,{FlagReg}        ' Flagregister lesen (nach fReg)
  SBRC  fReg,RS232DataBranch  ' Sprung, falls das RS232Data Bit gelöscht
  RJMP  RS232Receive4         ' sonst beenden (gesendetes Byte geht verloren)
'------------------------------------------------------------------------------
  lds   zReg,{RSBuffCount}    ' Zeichenzähler aus RAM lesen (nach zReg)
  push  YL                    ' Y-Pointer auf den Datenpuffer setzen
  push  YH
'  ldi  YL,low(RSBuffer)      ' Tabellenoffset im Datensegment
'  ldi  YH,high(RSBuffer)     ' .. so will's der Assembler
  Loadadr Rsbuffer(1) , Y     ' .. so will's BASCOM
'  LOADADR RSBuffString,Y     ' .. oder auch so
  add   YL,zReg               ' Zeichenzähler um eins erhöhen
  brcc  RS232Receive0         ' und zum Y-Pointer addieren
  inc   YH
Rs232receive0:
  cpi   mReg,Terminator       ' (LineFeed #10): Endekennzeichen
  brne  RS232Receive2
Rs232receive1:
  clr   mReg                  ' Zeichen = #10, dann #0 eintragen UND
  CLR   zReg                  ' Zeichenzähler ebenfalls auf #0
  SBR   fReg,RS232DataPresent ' Bit 7: Flag für Daten vollständig setzen
  sts   {FlagReg},fReg        '        im Flagregister setzen
  rjmp  RS232Receive3         '        MIT MASKE $80 !!!!
Rs232receive2:
  inc   zReg                  ' Anzahl gelesener Zeichen erhöhen
  cpi   zReg,CBuffsize        ' Puffer schon voll
  brsh  RS232Receive1         ' Sprung, falls ja (dann als #10 behandeln)
Rs232receive3:
  st    Y,mReg                ' Zeichen in Puffer eintragen
  sts   {RSBuffCount},zReg    ' Counter oder (#0 OR RS232Data) eintragen
  pop   YH
  pop   YL
'..............................................................................
Rs232receive4:                ' Lead-Out
  POP   fReg
  pop   zReg                  ' benutzte Register restaurieren
  pop   mReg                  ' sowiw flags wiederherstellen
  Out Sreg , Mreg
  pop   mReg
' RETI                        ' BASCOM ersetzt in diesem Fall, d.h. ISR-Routine
$end Asm                      ' die über ON 'Interrupt' 'Label' deklariert ist
Return                        ' dieses 'RETURN' durch 'RETI' (nicht RET)
'..............................................................................
'..............................................................................
'..............................................................................
 

Ü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)