Go Down

Topic: Problem mit mehreren UARTs (Mega <> ATtiny) (Read 5053 times) previous topic - next topic

combie

Auch wenn ich jetzt ein bisschen pingelig erscheine...
Der Tiny hat keine UART.
Auch keine 2 UARTs.

Im Grunde ist die falsche Benennung kein Problem, wenn man das richtige tut.
Aber mich bringt es, beim lesen von (Programm)Texten, immer wieder zum straucheln.
Ich glaube, dass auch Google viel auskunftsfreudiger ist, wenn man nach den richtigen Begriffen sucht.
Also nicht UART, sondern USART


Hier evtl was anpassungsfähiges.
Zumindest die empfangs ISR ist schon implementiert


Es ist offensichtlich, dass uns die Umstände alleine nicht glücklich oder unglücklich machen.
Es ist die Art unserer Reaktion darauf, die unsere Gefühle bestimmt.

Doc_Arduino

Hallo,

ihr drängt mich nun doch selbst umzuschreiben.  ;)
UART, USART, ja okay hat eine USART, wie der Mega.
Standardmäßig wird die im Arduino asyncron betrieben, wenn ich das richtig erkannt habe.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Ja, ein bisschen pingelig bin ich ja schon...
Sachte ich ja schon....

Quote
Standardmäßig wird die im Arduino asyncron betrieben, wenn ich das richtig erkannt habe.
Yes.


Quote
ihr drängt mich nun doch selbst umzuschreiben. 
Kannste so nicht sehen....
Mir ist es recht wurscht, was du tust...
Also, "wurscht", nicht im Sinne von "Gleichgültig", sondern im Sinne von "Selbst verantwortlich".

Und, wenn du es selber schreibst, will ich da gerne mal drüber schauen...
Testen kann ich leider nicht, kein 841 im Haus.





Es ist offensichtlich, dass uns die Umstände alleine nicht glücklich oder unglücklich machen.
Es ist die Art unserer Reaktion darauf, die unsere Gefühle bestimmt.

michael_x

Quote
mal ganz sachte. Ich habe nie gesagt das Hardware Serial schlecht ist.
Mein Einwand kam evtl. gestern abend falsch rüber:

Wenn es dein Ziel ist, das selber zu schreiben, sehr schön.
Man sollte sich aber schon ansehen, was es bereits gibt.

Und wenn das Ergebnis dann noch besser wird als das bereits vorhandene (in welcher Hinsicht auch immer), wären ich und wohl auch andere interessiert daran, was du combie zum Drüberschauen gibst.


Doc_Arduino

Hallo,

@ all: gut, dann spornt mich das an nun selbst zu machen.  ;)

@ Micha, kam wohl doch etwas missverstanden rüber., alles gut, keine Sorge.


ab jetzt nicht stören ...  :smiley-mr-green:
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

Hallo,

hatte mich etwas schwer getan den Interrupt anzuwenden.
Aktueller Code funktioniert erstmal. Der Receive Interrupt ist aktiv.
Der Empfang ist laut Test-Pin 3,1µs "blockiert".

Eigentlich wollte ich den Code von read_USART0() in den ISR (USART0_RX_vect) verfrachten, aber da meckert der Compiler wie wild, kann ich morgen posten wenn ich keine Lösung finde.

Das Atomic kann ich mir doch sparen, weil nur ein Byte gelesen bzw. übergeben wird, richtig?

Code: [Select]
/*
 * ATtiny841_USART_ISR_002.cpp
 *
 * Created: 24.02.2017 20:41:34
 *  Author: Doc_Arduino
 *     µC : ATtiny841 mit internen 8MHz Oszillator
 *
 * USART0 Empfang mit Interrupt, blockiert den Code nicht
 *
 * Interrupt-Vector Namen Übersicht:
 * C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\include\avr\iotn841.h
 */

#define F_CPU 8000000UL  // Systemtakt in Hz

#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <util/atomic.h>    // für cli() und sei() mit SREG Sicherung

#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))   // setzt das angegebene Bit auf 1
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))  // setzt (löscht) das angegebene Bit auf 0
#endif

/*
  UART Berechnungen des Wertes für das Baudratenregister aus Taktrate und gewünschter Baudrate
*/
#define BAUD 250000UL    // gewünschte Baudrate
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // sauber runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
#if ((BAUD_ERROR<995) || (BAUD_ERROR>1005))
  #error Systematischer Fehler der Baudrate greosser 0,5% und damit zu hoch!
#endif

volatile uint32_t millis_count; // ISR Timer 0 Variable
volatile uint32_t second_count; // ISR Timer 0 Variable
uint32_t last_millis;
uint32_t last_second;

const uint8_t SERIAL_BUFFER_SIZE = 20;
char Buffer_Serial_0[SERIAL_BUFFER_SIZE];
volatile char USART0_char;
volatile bool usart0_neues_Byte_vorhanden = false;

#define Pin_Led4_OUT sbi (DDRA,3) // PA3 Ausgang
#define Pin_Led4_EIN sbi (PORTA,3) // PA3 einschalten
#define Pin_Led4_AUS cbi (PORTA,3) // PA3 ausschalten

/* *** Funktion Deklarationen *** */
/* *** UART 0 *** */
void USART0_Init(); // Pin 8,9, TxD1/RxD1
void USART0_sendChar(unsigned char data);
void USART0_sendString (const char *s);
void USART0_send_uint32(uint32_t zahl);
unsigned char USART0_empfangen();
/* *** UARTs read and send *** */
bool read_USART0();
void handle_Serial_0_to_Serial_0();


uint32_t millis();
uint32_t seconds();
ISR(TIMER0_COMPA_vect);
void set_Timer0(); // Timer 0, millis, seconds


int main(void)
{  
// µC Takt langsam justieren zum testen

OSCCAL0 = 40; _delay_ms(100);
OSCCAL0 = 39; _delay_ms(100);
OSCCAL0 = 38; _delay_ms(100);
OSCCAL0 = 37; _delay_ms(100);

Pin_Led4_OUT; // PA3 Ausgang

USART0_Init();
set_Timer0(); // millis, seconds
    
    while (1)
    {  
Pin_Led4_EIN;
handle_Serial_0_to_Serial_0();
Pin_Led4_AUS;
}
}


/* *** Funktionen *** */

void USART0_Init()
{
UBRR0H  = UBRR_VAL >> 8; // set baud rate
UBRR0L  = UBRR_VAL & 0xFF;
UCSR0B  = (1<<RXEN0)|(1<<TXEN0); // enable receiver and transmitter
UCSR0B |= (1<<RXCIE0); // enable RX COMPLETE Interrupt
UCSR0C  = (1<<UCSZ01)|(1<<UCSZ00); // set frame format: 8data, 1stop bit
}


ISR (USART0_RX_vect) // USART0 receive complete ISR
{ /* wird ausgeführt, wenn ein Datenbyte im UDR0 liegt */

USART0_char = UDR0;
usart0_neues_Byte_vorhanden = true;
}

bool read_USART0()
{  
static uint8_t index = 0;
char c = 0;

if (usart0_neues_Byte_vorhanden == true) {
ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {
c = USART0_char;
usart0_neues_Byte_vorhanden = false; // Flag in ISR zurücksetzen
}
    
if (c >= 32 && (index < SERIAL_BUFFER_SIZE - 1)) {
Buffer_Serial_0[index++] = c;
}
else if ( (c == '\r' || c == '\n') && index > 0) {
Buffer_Serial_0[index] = '\0';
index = 0;
return true;
}
   }
   return false;
}


void handle_Serial_0_to_Serial_0 ()
{
if( read_USART0() == true)  {

if (strncmp(Buffer_Serial_0, "REQUEST", 7) == 0)  {
USART0_sendString("REQUEST USART_0-0"); USART0_sendChar('\n');
USART0_send_uint32( seconds() ); USART0_sendChar('\n');
}
else if (strncmp(Buffer_Serial_0, "GOOD", 4) == 0)  {
USART0_sendString("GOOD USART_0-0"); USART0_sendChar('\n');
USART0_send_uint32( millis() ); USART0_sendChar('\n');
}
else {
USART0_sendString("BACK USART0"); USART0_sendChar('\n');
USART0_sendString(Buffer_Serial_0); USART0_sendChar('\n');
USART0_send_uint32( seconds() ); USART0_sendChar('\n');
}
memset(Buffer_Serial_0,'\0',sizeof(Buffer_Serial_0));  // seriellen Buffer löschen
}
}


void USART0_sendChar( unsigned char data )
{
while ( !( UCSR0A & (1<<UDRE0)) ) // wait for empty transmit buffer
;
UDR0 = data; // Put data into buffer, sends the data
}



void USART0_sendString (const char *string)
{ // Vergleich auf ASCII Zeichen '\0' (NUL)
while (*string != 0x00) { // "String-Endezeichen" (Null-Terminator)
USART0_sendChar(*string); // vorderstes Zeichen senden
string++;
}
}


void USART0_send_uint32(uint32_t zahl)
{ // convert eine long Zahl zu einem String
char string[11];
ultoa(zahl, string, 10); // convert unsigned long to string, radix=10
USART0_sendString(string);
}


void set_Timer0 () // millis, seconds
{
cli(); // Interupts ausschalten
TCNT0 = 0; // Register Reset
TCCR0A = 0;
TCCR0B = 0;
TIMSK0 = 0;
TCCR0A = (1 << WGM01); // CTC Modus
OCR0A = 124; // TOP, (F_CPU/PRESCALER)/1000-1
TIMSK0 |= (1 << OCIE0A); // Interupts einschalten
TCCR0B |= (1 << CS01) | (1 << CS00); // Prescaler 64, Timer starten
sei();
}


uint32_t millis()
{
uint32_t value = 0;
ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
{
value = millis_count;
}
return value;
}


uint32_t seconds()
{
uint32_t value = 0;
ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
{
value = second_count;
}
return value;
}


ISR(TIMER0_COMPA_vect)
{
static uint32_t local_millis = 0;

millis_count++; // Zähler für Millisekunden
local_millis++;

if (local_millis > 999) {
second_count++; // Zähler für Sekunden
local_millis = 0;
}
}




Quote
Terminalausgabe:
GOOD USART_0-0
231024
REQUEST USART_0-0
231
Arduino Code:
Code: [Select]
void loop() { 

  handle_Serial_2_to_Serial_0();
 
  if (millis() - last_millis > 500) {
    last_millis = millis();

    if (toggle == true) {
      Serial2.println("REQUEST");
    }
    if (toggle == false) { 
      Serial2.println("GOOD");
    }
    toggle = !toggle;
  } 
 
} // loop Ende


Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

#21
Feb 25, 2017, 10:45 am Last Edit: Feb 25, 2017, 10:51 am by combie
Jain!

Wenn man
Code: [Select]
volatile char USART0_char;
volatile bool usart0_neues_Byte_vorhanden = false;

als zusammengehörige Daten betrachtet, ist bei deinem Verfahren  Atomic nötig.
Und zwar über Beide gleichzeitig, in einem Block.


Aber selbst dann noch können Zeichen verloren gehen, wenn deine Hauptschleife mal länger als 80µs braucht.

Musst du so mit RAM geizen, dass da keine 32 Byte FiFo mehr drin sitzt?
Ich würde eine solche einführen, damit Dateneingang und Verarbeitung besser entkoppelt sind.

Quote
Eigentlich wollte ich den Code von read_USART0() in den ISR (USART0_RX_vect) verfrachten,
Den Parser in die ISR rein?
Das halte ich für keine gute Idee.
Das schränkt die Wiederverwendbarkeit deiner "841 Serial Lib" doch sehr ein.

Es ist offensichtlich, dass uns die Umstände alleine nicht glücklich oder unglücklich machen.
Es ist die Art unserer Reaktion darauf, die unsere Gefühle bestimmt.

Doc_Arduino

#22
Feb 25, 2017, 11:21 am Last Edit: Feb 25, 2017, 11:27 am by Doc_Arduino
Hallo,

der Einlesecode muss eigentlich genau deshalb in die ISR, weil sonst Zeichen verloren gehen, wie du festgestellt hast, wenn die while/loop mehr als 40µs verdrödelt. Und das geht ganz schnell mit größeren Code. Ob ich mir ein FiFo Buffer leisten kann weiß ich noch nicht. Ich denke zwar schon, bin mir aber nicht sicher.  Ein 100 Byte Array verballer ich schon für die automatische Taktsyncronisierung zum einmessen.

Ich meine, dass Problem mit dem "Zeichen verloren gehen", tritt doch nur auf wenn man zu schnell sendet bzw. der ATtiny pausenlos empfangen müßte. Aber dann nützt auch ein Ringbuffer nichts mehr in meinen Augen. Irgendwann ist jeder Buffer voll wenn die Abarbeitung nicht hinterherkommt.

Ich hatte gestern Nacht das auch noch fertig gebracht den Code in die ISR zuverfrachten. Nur warfen mich vorher folgende Fehlermeldungen zurück. Erscheint für jede Benutzung von Buffer_Serial_0.


Quote
Fehler: invalid conversion from 'volatile char*' to 'const char*' [-fpermissive]  
    Nachricht: initializing argument 1 of 'int strncmp(const char*, const char*, size_t)'
Das hängt mit strncmp zusammen. Das klappt wegen dem zum volatile gemachten Buffer_Serial_0 Array nicht mehr.
Abhilfe schafft eine Pointer Typcast (wenn man das so richtig nennt) mit (char*).
Praktisch getestet funktioniert das.
Nur irgendwie gefällt mir das nicht, weiß auch nicht warum. Gibt es dafür eine bessere Lösung?
Ich meine nur einlesen und Auswertung macht ja keinen Sinn.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Doc_Arduino

Code: [Select]
#define F_CPU 8000000UL  // Systemtakt in Hz

#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <util/atomic.h>    // für cli() und sei() mit SREG Sicherung

#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))   // setzt das angegebene Bit auf 1
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))  // setzt (löscht) das angegebene Bit auf 0
#endif

/*
  UART Berechnungen des Wertes für das Baudratenregister aus Taktrate und gewünschter Baudrate
*/
#define BAUD 250000UL    // gewünschte Baudrate
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // sauber runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
#if ((BAUD_ERROR<995) || (BAUD_ERROR>1005))
  #error Systematischer Fehler der Baudrate greosser 0,5% und damit zu hoch!
#endif

volatile uint32_t millis_count; // ISR Timer 0 Variable
volatile uint32_t second_count; // ISR Timer 0 Variable
uint32_t last_millis;
uint32_t last_second;

const uint8_t SERIAL_BUFFER_SIZE = 20;
volatile char Buffer_Serial_0[SERIAL_BUFFER_SIZE];
volatile bool usart0_string_empfang_complete = false;     // Flag ob ein USART0 String komplett empfangen wurde
volatile bool usart0_Receive_Byte_vorhanden = false;

#define Pin_Led4_OUT sbi (DDRA,3) // PA3 Ausgang
#define Pin_Led4_EIN sbi (PORTA,3) // PA3 einschalten
#define Pin_Led4_AUS cbi (PORTA,3) // PA3 ausschalten

/* *** Funktion Deklarationen *** */
/* *** UART 0 *** */
void USART0_Init(); // Pin 8,9, TxD1/RxD1
void USART0_sendChar(unsigned char data);
void USART0_sendString (const char *s);
void USART0_send_uint32(uint32_t zahl);
/* *** UARTs read and send *** */
void handle_Serial_0_to_Serial_0();


uint32_t millis();
uint32_t seconds();
ISR(TIMER0_COMPA_vect);
void set_Timer0(); // Timer 0, millis, seconds


int main(void)

// µC Takt langsam justieren zum testen

OSCCAL0 = 40; _delay_ms(100);
OSCCAL0 = 39; _delay_ms(100);
OSCCAL0 = 38; _delay_ms(100);
OSCCAL0 = 37; _delay_ms(100);

Pin_Led4_OUT; // PA3 Ausgang

USART0_Init();
set_Timer0(); // millis, seconds
   
    while (1)
    {   
Pin_Led4_EIN;
handle_Serial_0_to_Serial_0();
Pin_Led4_AUS;
}
}


/* *** Funktionen *** */

void USART0_Init()
{
UBRR0H  = UBRR_VAL >> 8; // set baud rate
UBRR0L  = UBRR_VAL & 0xFF;
UCSR0B  = (1<<RXEN0)|(1<<TXEN0); // enable receiver and transmitter
UCSR0B |= (1<<RXCIE0); // enable RX COMPLETE Interrupt
UCSR0C  = (1<<UCSZ01)|(1<<UCSZ00); // set frame format: 8data, 1stop bit
}


ISR (USART0_RX_vect) // USART0 receive complete ISR
{ /* wird ausgeführt, wenn ein Datenbyte im UDR0 liegt */
   
static uint8_t index = 0;
char c = UDR0;

if (usart0_string_empfang_complete == false) { // wenn String in Verwendung, Daten verwerfen
if (c >= 32 && (index < SERIAL_BUFFER_SIZE - 1)) {
Buffer_Serial_0[index++] = c;
}
else if ( (c == '\r' || c == '\n') && index > 0) {
Buffer_Serial_0[index] = '\0';
index = 0;
usart0_string_empfang_complete = true;
}
}
}


void handle_Serial_0_to_Serial_0 ()
{
if( usart0_string_empfang_complete == true)  {

if (strncmp((char*)Buffer_Serial_0, "REQUEST", 7) == 0)  {
USART0_sendString("REQUEST USART_0-0"); USART0_sendChar('\n');
USART0_send_uint32( seconds() ); USART0_sendChar('\n');
}
else if (strncmp((char*)Buffer_Serial_0, "GOOD", 4) == 0)  {
USART0_sendString("GOOD USART_0-0"); USART0_sendChar('\n');
USART0_send_uint32( millis() ); USART0_sendChar('\n');
}
else {
USART0_sendString("BACK USART0"); USART0_sendChar('\n');
USART0_sendString((char*)Buffer_Serial_0); USART0_sendChar('\n');
USART0_send_uint32( seconds() ); USART0_sendChar('\n');
}
memset((char*)Buffer_Serial_0,'\0',sizeof(Buffer_Serial_0));  // seriellen Buffer löschen
usart0_string_empfang_complete = false;
}
}


void USART0_sendChar( unsigned char data )
{
while ( !( UCSR0A & (1<<UDRE0)) ) // wait for empty transmit buffer
;
UDR0 = data; // Put data into buffer, sends the data
}


void USART0_sendString (const char *string)
{ // Vergleich auf ASCII Zeichen '\0' (NUL)
while (*string != 0x00) { // "String-Endezeichen" (Null-Terminator)
USART0_sendChar(*string); // vorderstes Zeichen senden
string++;
}
}


void USART0_send_uint32(uint32_t zahl)
{ // convert eine long Zahl zu einem String
char string[11];
ultoa(zahl, string, 10); // convert unsigned long to string, radix=10
USART0_sendString(string);
}
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

#24
Feb 25, 2017, 12:32 pm Last Edit: Feb 25, 2017, 12:33 pm by combie
Quote
Ein 100 Byte Array verballer ich schon für die automatische Taktsyncronisierung zum einmessen
.
? ? ?

Brauchst du das die ganze Zeit über?
Es ist offensichtlich, dass uns die Umstände alleine nicht glücklich oder unglücklich machen.
Es ist die Art unserer Reaktion darauf, die unsere Gefühle bestimmt.

Doc_Arduino

Hallo,

ich messe 100 Pegelwechsel, filtere falsche Werte raus und mittel dann die gültigen. Perfekte Messung und damit perfekte OSCCAL Kalibrierung. Ich könnte vielleicht noch auf 50 runtergehen. Müßte ich ggf. neu austesten.
Ich benötige die eigentlich nur beim Kaltstart. Wollte mir aber die Option offenhalten im laufenden Betrieb eine Nachkalibrierung durchführen zu lassen. Wenn der ATtiny zum Bsp. kälter oder wärmer wurde. Oder wenn er den Kontakt verloren hat, aus welchen Gründen auch immer. Temporär könnte man das Array löschen und wieder anlegen bei Bedarf. Nur wie weiß ich nicht recht. Irgendwas mit malloc sicherlich.

Die Pinfunktion der USART0 wird demnach zur Kalibrierung kurzzeitig als normale Pinfunktion umkonfiguriert und geht danach wieder in USART Betrieb. Bei dem Test bin ich dann wie Eingangs erwähnt abgestorben wegen dem zufällig erkannten Problem mit den USARTs und alten Code.

Den Einlesecode in der ISR findest du immer noch nicht gut? Nur wie dann? Alles was außerhalb der ISR gemacht wird birgt die Gefahr das ein Byte verloren geht wenn es nicht rechtzeitig abgeholt wird. Ich denke da sind wir einer Meinung.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

#26
Feb 25, 2017, 10:50 pm Last Edit: Feb 25, 2017, 11:38 pm by combie
Ich rolle das mal von hinten auf...


Quote
.... das ein Byte verloren geht wenn es nicht rechtzeitig abgeholt wird. Ich denke da sind wir einer Meinung.
Das wollen wir nicht!
Zumindest für mich bin ich sicher: Möglichst keine Bytes verlieren!

Also reden wir über das "Wie?'" und auch, über das "Wie man es besser nicht tut".

Quote
Alles was außerhalb der ISR gemacht wird birgt die Gefahr das ein Byte verloren geht
Nur wenn du kein FiFo etablierst.

Quote
Kalibrierung
Aha, dafür die Tabelle...
OK, bei 8MHz und 250000Baud, wirds ohne  Kalibrierung nicht gehen.
Ist wenigstens die Versorgungsspannung stabil, oder direkt am LiPo?

Die  Kalibrierung!
Das ist eine andere Baustelle....
Da gibts noch interessante Möglichkeiten...



Quote
Die Pinfunktion der USART0 wird demnach zur Kalibrierung kurzzeitig als normale Pinfunktion umkonfiguriert und geht danach wieder in USART Betrieb.
Wenn du kalibrierst, brauchst du keinen seriellen Buffer.
Wenn du seriell arbeitest, kannst du nicht gleichzeitig kalibrieren, zumindest nicht mit deiner Methode.
? ? ?


Quote
Temporär könnte man das Array löschen und wieder anlegen bei Bedarf. Nur wie weiß ich nicht recht. Irgendwas mit malloc sicherlich
.

Von malloc möchte ich abraten.
Gegenvorschlag:
Eine Struktur für die FIFOs, und ihre Zeiger.
Eine Struktur für die Kalibrierung.

Dann eine Union, in der beide Überlagert stecken.

Dann brauchst du nur noch ein Semaphor/Mutex/Lock/Verriegelung, welche eine gleichzeitige Verwendung ausschließt.



Ahnst du, was ich meine?
Oder liege ich völlig daneben?
Es ist offensichtlich, dass uns die Umstände alleine nicht glücklich oder unglücklich machen.
Es ist die Art unserer Reaktion darauf, die unsere Gefühle bestimmt.

Doc_Arduino

Hallo,

die Kalibrierung steht inkl. Umschaltung schon länger. Bei ausgiebigen Tests mit 2 USARTs stieß ich dann aber auf Probleme worauf der Thread entstanden ist.  Ich komme aber aktuell auf neue Gedanken um die Umschaltung vielleicht loszuwerden. Auf Grund der jetzigen Benutzung der USART Interrupts. Wobei dann die Präzision leidet bzw. die Kalibrierung verlängert sich zeitlich um das zehnfache. Mindestens 5fach.  Aktuell bin ich bei unter 0,5%. Das Thema ist aber komplex, kann ich nicht in paar Zeilen erklären, würde einen extra Thread erfordern. Können wir erstmal ignorieren.

Eine Frage gebe es jedoch dazu. Kann man ein global initialisiertes Array später einmalig verkleinern?
Die Doppelnutzung des Array für beide Anwendungen gefällt mir sehr gut. Das wäre mir nicht eingefallen.

Übrigens es wurde auch nie gleichzeitig kalibriert und empfangen. Deswegen die Umschaltung.

Zurück zum Hauptthema. USART empfangen & senden ohne Blockierung.

Irgendwie komme ich von dem Gedanken nicht los, dass auch der beste und größte Ringbuffer der Welt nichts nützt, wenn die Abarbeitung aus irgendwelchen Gründen nicht hinterherkommt um die eingelesenen Strings wieder auszulesen/auszuwerten. Irgendwann wird der Ringbuffer einfach überschrieben werden müssen mit neuen Werten und die alten gehen damit verloren. Oder umgekehrt neue Bytes werden nicht angenommen und verworfen.

Deswegen bin ich überzeugt davon, dass die Einlesefunktion in den Receive Interrupt gehört. Was du im Moment leider ablehnst. Damit meine ich das abholen vom UDRn Register und in den Buffer schieben. Was nützt mir ein Receiver Interrupt der nur das Byte aus dem UDRn abholt, wenn die eigentliche Buffer-Funktion in der loop unvorhersehbar mal drankommt und dadurch ganz sicher später als aller 40µs. Dadurch gehen ganz sicher Zeichen verloren.

Sorry wenn ich da immer noch unterschiedlicher Auffassung bin. Ansonsten bitte anders erklären/begründen.

Aus meiner Sicht benötige ich noch keinen Ringbuffer. Ich sende vom Mega aus nicht permanent. Aber wenn ich sende muss es schnell gehen, deswegen die 250kBaud. Anfrage und Antwort.

Eine Frage blieb unbeantwortet. Ist der Typcast (char*) die einzig richtige Möglichkeit gewesen?
#22 untere Hälfte.


struct und union sind im einzelnen klar. Für meinen einfachen Buffer und Kalibrierbuffer verschachtelt sicherlich eine neue spannende Aufgabe.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

#28
Feb 26, 2017, 11:07 pm Last Edit: Feb 26, 2017, 11:35 pm by combie
Quote
Eine Frage blieb unbeantwortet. Ist der Typcast (char*) die einzig richtige Möglichkeit gewesen?
#22 untere Hälfte.
Ich weiß nicht ob die richtig ist...
Es geht halt das volatile Attribut verloren.
Wobei ich mir denke: Der Bereich ist nicht ohne Grund "volatile".

Die Alternative wäre, eine lokale Kopie anlegen und damit arbeiten.
-- nicht schön --

Quote
Deswegen bin ich überzeugt davon, dass die Einlesefunktion in den Receive Interrupt gehört. Was du im Moment leider ablehnst. Damit meine ich das abholen vom UDRn Register und in den Buffer schieben. Was nützt mir ein Receiver Interrupt der nur das Byte aus dem UDRn abholt, wenn die eigentliche Buffer-Funktion in der loop unvorhersehbar mal drankommt und dadurch ganz sicher später als aller 40µs. Dadurch gehen ganz sicher Zeichen verloren.

Sorry wenn ich da immer noch unterschiedlicher Auffassung bin. Ansonsten bitte anders erklären/begründen.
Im Grunde ist das ja alles dein Problem...
Für mich ist das ein klassisches PAL (Ein Problem Anderer Leute)
Ich bin nicht daran interessiert dir meine Denkweise aufzudrücken.
Aber wenn du es hören möchtest, will ich gerne Stellung beziehen.
Und ich freue mich, wenn du damit was anfangen kannst!

So...
Angenommen, du hast eine 32 Byte FiFo..
Dann dauert es 33*40µs =1320µs bis du das erste Zeichen da abgeholt haben musst.
Und auch das nur, wenn mehr als 32 Zeichen auf einmal gesendet werden.

Tipp:
Im Loop sobald als möglich die Daten aus der Fifo abholen und in einen lokalen/globalen Puffer zwischenspeichern. Den kannst du dann ganz in Ruhe überprüfen/behandeln.



Quote
Irgendwie komme ich von dem Gedanken nicht los, dass auch der beste und größte Ringbuffer der Welt nichts nützt, wenn die Abarbeitung aus irgendwelchen Gründen nicht hinterherkommt um die eingelesenen Strings wieder auszulesen/auszuwerten.
Ich sachs mal so...
Das Problem wirst du nie los!
Du kannst nur "Staustrecken" einrichten, um das Problem zu mildern.

So auch der Ringbuffer für die Sendedaten.
Der bringt auch reichlich Zeit für loop.
Bis jetzt wartest du ja noch, bis jedes einzelne Zeichen raus ist. Das ist Zeitverplemperung.


Zusammenfassung:
Mit der FiFo Methode kannst du nur in Schwierigkeiten kommen, wenn du es nicht schaffst, dass alle 1,3ms ein Loop Durchlauf stattfindet und die gesendeten Daten länger als 32 Byte sind.

Dir ist das Problem, dir ist die Entscheidung.
Es ist offensichtlich, dass uns die Umstände alleine nicht glücklich oder unglücklich machen.
Es ist die Art unserer Reaktion darauf, die unsere Gefühle bestimmt.

Doc_Arduino

Hallo,

ich bin immer an neuen Denkansätzen interessiert und sortiere dann für mich und die Anwendung passend aus.

Typcast, vielleicht mach ich dazu nochmal einen Thread auf.

Wegen dem FiFo. Ich glaube langsam wir reden irgendwie aneinander vorbei und reden doch vom gleichen.
Ist ja im Grunde das was ich geschrieben hatte.  ;)
Ich dachte dich stört die Einlesefunktion in der ISR? Die blockiert nichts.
Weil 1ms loop Zeit ist schnell erreicht, finde ich und immer noch schnell für den Rest vom Code.
Der große Nachteil beim kleinen ATtiny ist der zusätzliche Buffer im RAM um vom Ringbuffer zum auswerten zu kommen damit der Ringbuffer wieder schnell frei wird.

Den Sende-Interrupt kann ich noch einbauen. Wobei das nicht unbedingt notwendig ist und wieder einen Buffer im RAM erfordert. Gut das wäre dann der Ringbuffer für senden und empfangen.  :)

Auf Fälle war es gut das wir darüber gesprochen haben. Ich lasse mir das immer mehrfach durch den Kopf gehen. Schon alleine deshalb um nicht alle Naselang den Code umzukrempeln. Ich werde darüber grübeln.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Go Up