UART im NON INTERRUPT- oder INTERRUPT-Modus bei Verwendung von VUSB

Ich arbeite an der UART-Datenübertragung von einem ATmega8 zum anderen, während der Empfänger VUSB ausführt, das als HID-Maus zum PC fungiert.

UART obwohl init mit 9600 , wird später auf maximale Geschwindigkeit gesetzt -> UBRR = 0;

Probleme :

  1. VUSB ist auf beiden Interrupt-basierten Komms nicht stabil. oder nicht unterbrechungsbasierte Kommunikation.
  2. Ich hatte nur einmal Erfolg, es stabil zu haben ... aber die empfangenen Daten waren Müll.

Wie überwinde ich diese Probleme ..

machte ein kleines Protokoll für Daten ..

SYNC_START XY END_SYNC

der Sendercode:

//////////////////////////////////////////////////////////////////////////
//Defines
//////////////////////////////////////////////////////////////////////////
#define F_CPU       16000000UL
#define true        0x01
#define false       0x00
#define uchar       unsigned char
#define uint        unsigned int

#define START_SYNC_BYTE 0b10101010
#define END_SYNC_BYTE   0b01010101
//////////////////////////////////////////////////////////////////////////

#include <avr/io.h>
#include <util/delay.h>

#include "uart/UART.h"
#include "IMU.h"

//////////////////////////////////////////////////////////////////////////
//GLOBAL VARIABLES
//////////////////////////////////////////////////////////////////////////
uint X=0,Y=0;
//////////////////////////////////////////////////////////////////////////


int main(void)
{
    i2c_init();
    WakeUpIMU();

    UART_Init(9600,true,false,false);

    UBRRH = 0;
    UBRRL = 0;


    while(1)
    {
        X = Get16Bits(MPU6050_RA_ACCEL_XOUT_H);
        Y = Get16Bits(MPU6050_RA_ACCEL_YOUT_H);

        BlockingTransmitt(START_SYNC_BYTE);
        BlockingTransmitt(START_SYNC_BYTE);
        BlockingTransmitt(X);
        BlockingTransmitt(Y);
        BlockingTransmitt(END_SYNC_BYTE);

        _delay_ms(5);
    }
}

Der Empfängercode:

//////////////////////////////////////////////////////////////////////////
//Defines
//////////////////////////////////////////////////////////////////////////
#define F_CPU       16000000UL
#define true        0x01
#define false       0x00
#define uchar       unsigned char
#define uint        unsigned int

#define START_SYNC_BYTE 0b10101010
#define END_SYNC_BYTE   0b01010101
//////////////////////////////////////////////////////////////////////////

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <util/delay.h>

#include "uart/UART.h"
#include "usbdrv/usbdrv.h"

//////////////////////////////////////////////////////////////////////////
//GLOBAL VARIABLES
//////////////////////////////////////////////////////////////////////////
uint X,Y;
bool WaitingForX=false,WaitingForY=false;
bool TransmissionComplete = false;
//////////////////////////////////////////////////////////////////////////



PROGMEM const char usbHidReportDescriptor[52] =
{ /* USB report descriptor, size must match usbconfig.h */
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x02,                    // USAGE (Mouse)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x09, 0x01,                    //   USAGE (Pointer)
    0xA1, 0x00,                    //   COLLECTION (Physical)
    0x05, 0x09,                    //     USAGE_PAGE (Button)
    0x19, 0x01,                    //     USAGE_MINIMUM
    0x29, 0x03,                    //     USAGE_MAXIMUM
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
    0x95, 0x03,                    //     REPORT_COUNT (3)
    0x75, 0x01,                    //     REPORT_SIZE (1)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x75, 0x05,                    //     REPORT_SIZE (5)
    0x81, 0x03,                    //     INPUT (Const,Var,Abs)
    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
    0x09, 0x30,                    //     USAGE (X)
    0x09, 0x31,                    //     USAGE (Y)
    0x09, 0x38,                    //     USAGE (Wheel)
    0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
    0x25, 0x7F,                    //     LOGICAL_MAXIMUM (127)
    0x75, 0x08,                    //     REPORT_SIZE (8)
    0x95, 0x03,                    //     REPORT_COUNT (3)
    0x81, 0x06,                    //     INPUT (Data,Var,Rel)
    0xC0,                          //   END_COLLECTION
    0xC0,                          // END COLLECTION
};

typedef struct{
    uchar   buttonMask;
    char    dx;
    char    dy;
    char    dWheel;
}report_t;


static report_t reportBuffer;
static uchar    idleRate;

usbMsgLen_t usbFunctionSetup(uchar data[8])
{
    usbRequest_t    *rq = (void *)data;

    /* The following requests are never used. But since they are required by
    * the specification, we implement them in this example.
    */
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){    /* class request type */
        if(rq->bRequest == USBRQ_HID_GET_REPORT){  /* wValue: ReportType (highbyte), ReportID (lowbyte) */
            /* we only have one report type, so don't look at wValue */
            usbMsgPtr = (void *)&reportBuffer;
            return sizeof(reportBuffer);
            }else if(rq->bRequest == USBRQ_HID_GET_IDLE){
            usbMsgPtr = &idleRate;
            return 1;
            }else if(rq->bRequest == USBRQ_HID_SET_IDLE){
            idleRate = rq->wValue.bytes[1];
        }
    }
    else{
        /* no vendor specific requests implemented */
    }
    return 0;   /* default for not implemented requests: return no data back to host */
}



int main(void)
{
    uchar i;

    wdt_enable(WDTO_1S);

    usbInit();
    usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
    i = 0;
    while(--i){             /* fake USB disconnect for > 250 ms */
        wdt_reset();
        _delay_ms(1);
    }
    usbDeviceConnect();

    UART_Init(9600 , false , true , false);
    UBRRH = 0;
    UBRRL = 0;

    sei();

    while(1)
    {
        wdt_reset();

        usbPoll();

        RecieveUARTdata();


        if(TransmissionComplete && usbInterruptIsReady()){
            /* called after every poll of the interrupt endpoint */
            usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
        }

    }
    return 0;
}

void ResetValues(){
    X=0;Y=0;
    WaitingForX=false;
    WaitingForY=false;
}



void RecieveUARTdata(){
    //Get the data is available by checking the RXC in UCSRA
    if ( UCSRA & (1<<RXC) )
    {
        uint data = UDR;
        //if the data received is START SYNC DATA
        if(data==START_SYNC_BYTE){
            WaitingForX = true;return;
        }

        else {
            if(WaitingForX){
                X=data; WaitingForX=false;
                WaitingForY=true;return;
            }
            else if(WaitingForY && !WaitingForX){
                Y=data; WaitingForY=false;return;
            }
            else if(!WaitingForX && !WaitingForY && (UDR==END_SYNC_BYTE)){
                reportBuffer.dx = X;
                reportBuffer.dy = Y;
                TransmissionComplete = true;return;
            }else ResetValues();
            return;
        }
    }
}
Ich bezweifle, dass das UARt-Modul mit einem Baudraten-Teiler von 0 arbeiten soll. Versuchen Sie es zumindest auf 1 oder 2 einzustellen.
@brhans UBRR = 0 ist in Ordnung. B A u D = F Ö S C / ( 16 ( U B R R + 1 ) )
@Akash, Sie sollten das UBRRegister nur einmal lesen, nicht mehrmals. Es gibt einen FIFO auf dem UART-Block und wenn Sie das Register lesen, geht es weiter zum nächsten Wert im FIFO.
if(UDR==START_SYNC_BYTE){liest den Wert und vergisst ihn. ...X=UDR;liest es ein zweites Mal, was den Wert verfälschen kann. Sie sollten tun uint8_t in = UDR;und dannif(in==START_SYNC_BYTE){...X=in;
Drittens, verwenden Sie einen Kristall? Wenn ja, sind es 12 MHz? Wenn nicht, haben Sie den internen Oszillator auf 12,8 MHz kalibriert? (Sie können dies tun, indem Sie D- mit einem Interrupt-Pin verbinden und VUSB korrekt konfigurieren.)
Ja .. Eigentlich habe ich es so gemacht, wie du es vorher gesagt hast, aber selbst es hat nicht funktioniert .. Ich verwende einen externen Quarz mit 16 MHz .. Ich werde den Code aktualisieren ...
@TomCarpenter Ich habe den Code bearbeitet und aktualisiert
Die andere Sache ist, dass Sie anscheinend einen 16-Bit-Wert für X und einen anderen für Y senden. Aber dann erhalten Sie einen 8-Bit-Wert für X und Y. Wo sind die anderen beiden Bytes geblieben?
Eigentlich stört mich das nicht, weil meine Werte von 20 bis -20 reichen, also bin ich gut damit. Entschuldigung, ich habe es in der Frage nicht erwähnt
Wahrscheinlich nicht verwandt, sollte aber nicht vorhersei() kommen ? usbPoll()
Das war ein Fehler.. Code aktualisiert
Welche UART-Bibliothek verwenden Sie und was bewirken die booleschen Parameter darin UART_Init(9600 , false , true , false)?
Selbst geschriebene Bibliothek .. 9600 ist Baudrate .. 1 bool ist für tx on .. 2 bool ist für RX on .. 3 bool ist für Interrupt-Modus on ..

Antworten (1)

Es gibt ein Hauptproblem, auf das in den Kommentaren hingewiesen wurde:

if ( UCSRA & (1<<RXC) )
{
    uint data = UDR;
    ...
        else if(!WaitingForX && !WaitingForY && (UDR==END_SYNC_BYTE)){
            ...
    }
}

In diesem Teil lesen Sie von einer leeren UDR, da die END_SYNC_BYTEzuvor gespeichert wurde, sodass diese Aussage immer falsch sein wird.

Der weniger komplizierte Weg besteht darin, jedes eingehende Byte im FIFO-Puffer zu speichern (oder sogar eine Interrupt-basierte Bibliothek zu verwenden , die mit v-usb umgehen kann) und die gesamte Nachricht in einem Durchgang zu verarbeiten.