ATmega328p und UART

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: ATmega328p und UART

Beitrag von Timm Thaler »

Mathias hat geschrieben:Irgendwie setzt mich der AVR in das 8088er-Zeitalter zurück, da hatte man auch jedes Byte optimiert. :wink:


Man muss nicht jedes Byte optimieren, das muss ich mir auch abgewohnen. Aber Divisionsroutinen fressen immer richtig viel Rechenzeit, deswegen versucht man die weitgehend zu vermeiden oder durch 2^n-Divisionen (div 2, div 4, ... div 256) zu ersetzen, dann kann der Compiler mit shift-Befehlen arbeiten.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ATmega328p und UART

Beitrag von Mathias »

Aber Divisionsroutinen fressen immer richtig viel Rechenzeit, deswegen versucht man die weitgehend zu vermeiden oder durch 2^n-Divisionen (div 2, div 4, ... div 256) zu ersetzen, dann kann der Compiler mit shift-Befehlen arbeiten.
Dies war schon beim 8088er der Fall.
So nebenbei, beim ATtiny muss man das auch bei Multiplikationen beachten, da dieser auch dies nicht Hardwaremässig kann.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ATmega328p und UART

Beitrag von Mathias »

Ich wollte jetzt mal einen Text mit dem Empfangspuffer machen.

Code: Alles auswählen

const
  CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz.
  Baud = 9600;          // Baudrate
  UCSZ01 = 2;           // Gibt es nicht in der Unit Atmega328p.
  teiler = CPU_Clock div (2 * Baud) - 1;
  teilerH = teiler shr 8;
  teilerL = teiler mod $100;
 
  procedure UART_RX_Empfang; public Name 'USART__RX_ISR'; interrupt;
  begin
    PORTB := PORTB or (1 shl 5);
  end;
 
  procedure UARTInit;
  begin
    UBRR0H := teilerH;
    UBRR0L := teilerL;
 
    UCSR0A := UCSR0A or (0 shl U2X0);
    UCSR0B := UCSR0B or (1 shl TXEN0) or (1 shl RXEN0) or (1 shl RXCIE0);
    UCSR0C := UCSR0C or (1 shl UMSEL0) or (1 shl UCSZ01) or (1 shl UCSZ0);
 
    DDRD := DDRD or (1 shl 4);
  end;     
 
begin
  DDRB := DDRB or (1 shl 5); // Pin 13 Output
  UARTInit;
  repeat
  until 1 = 2;
end.

Die LED an Pin13 geht nicht an, so wie es aussieht, wir der Interrupt nicht ausgelöst.
Wieso ?
Wen ich in Terminal etwas eingebe, leuchtet die LED RX wie erwartet kurz auf.

Der Procedure-Name habe ich aus der Unit ATmega328p.

Code: Alles auswählen

procedure USART__RX_ISR; external name 'USART__RX_ISR'; // Interrupt 18 USART Rx Complete


Noch etwas, wen ich es richtig verstanden habe, gibt es beim AVR keinen Hardware-Empfangspuffer ?
Zuletzt geändert von Mathias am Mo 23. Okt 2017, 19:55, insgesamt 1-mal geändert.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: ATmega328p und UART

Beitrag von Timm Thaler »

Mathias hat geschrieben:Ich wollte jetzt mal einen Text mit dem Empfangspuffer machen.


Wie sieht UartInit aus?

Mathias hat geschrieben:Noch etwas, wen ich es richtig verstanden habe, gibt es beim AVR keinen Hardware-Empfangspuffer ?


Doch, wohl. Einen 2-Byte FIFO. Während ein Byte empfangen wird, kannst Du das vorherige auslesen.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ATmega328p und UART

Beitrag von Mathias »

Wie sieht UartInit aus?

Ups vergessen, habe sie oben angehängt.

Doch, wohl. Einen 2-Byte FIFO. Während ein Byte empfangen wird, kannst Du das vorherige auslesen.

Sowas habe ich mir fast gedacht, ansonsten könnte man sich die Übung mit dem Puffer sparen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: ATmega328p und UART

Beitrag von Timm Thaler »

SEI

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ATmega328p und UART

Beitrag von Mathias »

Timm Thaler hat geschrieben:SEI

Ich glaube ich spinne. :roll:
Da es nicht ging, habe ich es mit Arduino und sei(); probiert, es funktionierte nicht.
Ich habe es hier abgeguckt: https://www.mikrocontroller.net/article ... l/Der_UART

Code: Alles auswählen

void UARTInit(){
    UBRR0 = teiler;
 
    UCSR0A |= (0 << U2X0);
    UCSR0B |= (1 << TXEN0) | (1 << RXEN0) | (1 << RXCIE0);
    UCSR0C |= (1 << UMSEL00) | (1 << UCSZ01) | (1 << UCSZ00);
 
    DDRD = DDRD or (1 << 4);
 
    sei();
 }

Irgendwie hat es im Arduino Müll.
Aber im Pascal-Code klappt es jetzt.

Code: Alles auswählen

  procedure UART_RX_Empfang; public Name 'USART__RX_ISR'; interrupt;
  begin
    PORTB := PORTB or (1 shl PB5);
  end;
 
  procedure UARTInit;
  begin
    UBRR0 := teiler;
 
    UCSR0A := UCSR0A or (0 shl U2X0);
    UCSR0B := UCSR0B or (1 shl TXEN0) or (1 shl RXEN0) or (1 shl RXCIE0);
    UCSR0C := UCSR0C or (1 shl UMSEL0) or (1 shl UCSZ01) or (1 shl UCSZ0);
 
    DDRD := DDRD or (1 shl 4);
 
    sei;
  end;

Irgendwie hat es im Arduino Müll.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: ATmega328p und UART

Beitrag von Timm Thaler »

Das ist das Problem beim Arduino: Du weisst nicht, was der noch im Hintergrund so treibt.

Das SEI solltest Du vor das Repeat im Hauptprogramm setzen. Es gibt alle Interrupts frei. Also auch Timerinterrupts und so. Wenn Du das in UartInit hast und danach einen Timerinterrupt initialisierst, kann das Probleme geben, ebenso wenn Du UartInit rausnimmst, gehen plötzlich alle anderen Interrupts auch nicht mehr.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ATmega328p und UART

Beitrag von Mathias »

Stimmt dies das der AVR zum Start im cli-Modus läuft ?

Ich habe heute Abend, das Ganze mit einem einfachen Buffer probiert, so halbwegs funktioniert es schon. Es kommen zwischendurch fehlerhafte Zeichen an, aber dies könnte auch beim Senen passieren.
Aber das werde ich morgen nochmals genauer angucken.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: ATmega328p und UART

Beitrag von Timm Thaler »

Mathias hat geschrieben:Stimmt dies das der AVR zum Start im cli-Modus läuft ?


Würd ich mich nicht drauf verlassen. Bei mir kommt gleich als Erstes ein cli, dann die Initialisierungen, dann ein sei.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ATmega328p und UART

Beitrag von Mathias »

Hier probiere ich es mal mit einem Empfangspuffer.
Nur kommt leider kommt im Schnitt jedes 20igste Zeichen fehlerhaft an.
Es spielt keine Rolle, ob ich es 9600 oder 115200 Baud mache.

Code: Alles auswählen

const
  PB5 = 5;
  UCSZ01 = 2;           // Gibt es nicht in der Unit Atmega328p.
  CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz.
  Baud = 115200;          // Baudrate
//  Baud = 9600;          // Baudrate
  teiler = CPU_Clock div (2 * Baud) - 1;
 
var
  zeiger: integer;
  buf: array[0..255] of byte;
 
 
  procedure UART_RX_Empfang; public Name 'USART__RX_ISR'; interrupt;
  begin
    buf[zeiger] := UDR0;
    Inc(zeiger);
  end;
 
  procedure UARTInit;
  begin
    UBRR0 := teiler;
 
    UCSR0A := UCSR0A or (0 shl U2X0);
    UCSR0B := UCSR0B or (1 shl TXEN0) or (1 shl RXEN0) or (1 shl RXCIE0);
    UCSR0C := UCSR0C or (1 shl UMSEL0) or (1 shl UCSZ01) or (1 shl UCSZ0);
 
    DDRD := DDRD or (1 shl 4);
  end;
 
  procedure UARTSendChar(c: char);
  begin
    while UCSR0A and (1 shl UDRE0) = 0 do begin
    end;
    UDR0 := byte(c);
  end;
 
  function UARTReadChar: char;
  begin
    while UCSR0A and (1 shl RXC0) = 0 do begin
    end;
    Result := char(UDR0);
  end;
 
  procedure UARTSendString(s: ShortString);
  var
    i: integer;
  begin
    for i := 1 to length(s) do begin
      UARTSendChar(s[i]);
    end;
  end;
 
var
  i: integer;
 
begin
  DDRB := DDRB or (1 shl UMSEL0); // Pin 13 Output
  zeiger := 0;
 
  cli;
  UARTInit;
  sei;
  repeat
    if zeiger > 3 then begin
      for i := 0 to 3 do begin
        UARTSendChar(char(buf[i]));
      end;
      UARTSendString(' Hello World !'#13#10);
      zeiger := 0;
    end;
  until 1 = 2;
end.

Wen ich konstant die 'x' drücke, bekomme ich folgende Ausgabe.
Ich kann auch ein anderes Zeichen drücken, dies spielt keine Rolle.

Was habe ich übersehen ?

Code: Alles auswählen

xxxx Hello World !
xxxx Hello World !
x�xx Hello World !
xxxx Hello World !
xxx� Hello World !
xxxx Hello World !
xxxx Hello World !
xxxx Hello World !
xx�x Hello World !
xxx� Hello World !
xxxx Hello World !
�xxx Hello World !
x�xx Hello World !
xxxx Hello World !
xxxx Hello World !
xxxx Hello World !
xxxx Hello World !
xxxx Hello World !
xxxx Hello World !
xxxx Hello World !
�xxx Hello World !


Ein zweiter Versuch, ich gebe aus was gerade rein kommt.
Hier kommt jedes Zeichen falsch raus.
Wen ich zB. die 'x' drücke, dann kommen fast alles 'y'. Zwischen durch kommt mal ein 'x' raus.
Weiter Ausgaben:
e --> u
a --> e
i --> m

Code: Alles auswählen

procedure UART_RX_Empfang; public Name 'USART__RX_ISR'; interrupt;
begin
  UARTSendChar(char( UDR0));
end;

Könnte dies einen Zusammenhang mit UDR0 haben ?
Da ich fast gleichzeitig lese und schreibe ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ATmega328p und UART

Beitrag von Mathias »

Wieso gibt es hier Übertragungsfehler ?

Ich habe das Programm mal aufs Minimum abgespeckt.

Ich mal die in die Interruptschleife eingefügt, aber ohne Erfolg.

Code: Alles auswählen

while UCSR0A and (1 shl RXC0) = 0 do begin end;

Ist die Schnittstelle etwa doch nicht bidirektional ?
Auch wen ich nur 9600Baud nehme, bleibt der Fehler.

Code: Alles auswählen

program Project1;
{$o-}
 
  procedure sei; assembler;
  asm
           Sei
  end;
 
  procedure cli; assembler;
  asm
           Cli
  end;
 
const
  UCSZ01 = 2;           // Gibt es nicht in der Unit Atmega328p.
  CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz.
    Baud = 115200;          // Baudrate
//  Baud = 9600;          // Baudrate
  teiler = CPU_Clock div (2 * Baud) - 1;
 
  procedure UARTInit;
  begin
    UBRR0 := teiler;
 
    UCSR0A := (0 shl U2X0);
    UCSR0B := (1 shl TXEN0) or (1 shl RXEN0) or (1 shl RXCIE0);
    UCSR0C := (1 shl UMSEL0) or (1 shl UCSZ01) or (1 shl UCSZ0);
 
    DDRD := DDRD or (1 shl 4);
  end;
 
  procedure UARTSendChar(c: Byte);
  begin
    while UCSR0A and (1 shl UDRE0) = 0 do begin
    end;
    UDR0 := byte(c);
  end;
 
  procedure UART_RX_Empfang; public Name 'USART__RX_ISR'; interrupt;
  begin
//    while UCSR0A and (1 shl RXC0) = 0 do begin
//    end;
    UARTSendChar(UDR0);
  end;
 
begin
  cli;
  UARTInit;
  sei;
 
  repeat
  until 1 = 2;
end.


Die Ausgabe im Terminal, die Buchstabenreihe habe ich als Eingabe gedrückt.
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq�qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqxxxxxxxxxxxx��x�xxxxxx�xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx�xxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzzzzz�zzzzzzzzzzzzzzzz�zzzzzzzzzzz�zzzzzzzzzzzzz�zyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy�yyyyyyyyyyy�yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy�yyyyyyyyyyyyyyyyyy�yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy�zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz�zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz�zzzzzzzzzzzzz
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: ATmega328p und UART

Beitrag von Timm Thaler »

Wenn es bei anderen funktioniert und bei Dir nicht, könnte der Fehler vielleicht nicht bei den anderen liegen. Rx und Tx geht gleichzeitig, ist so.

Datenblatt Seite 190, 115kbaud ist grenzwertig bei 16MHz, erklärt aber nicht das Problem bei 9600baud.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ATmega328p und UART

Beitrag von Mathias »

[quote115kbaud ist grenzwertig bei 16MHz[/quote]
Mit dem Arduino Serial sind sogar 1000000Baud möglich.

Keine Idee, was in meinem Code falsch ist, das es bei mir nicht mal mit 9600Baud klappt ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: ATmega328p und UART

Beitrag von Timm Thaler »

Und? Hast Du mal ins Datenblatt geschaut?

16MHz durch 1000000 geht ohne Rest.
16MHz durch 115200 geht nicht ohne Rest.

Antworten