UART en modo SIN INTERRUPCIÓN o INTERRUPCIÓN mientras usa VUSB

Estoy trabajando en la transferencia de datos UART de un ATmega8 a otro mientras el receptor ejecuta VUSB actuando como HID Mouse para la PC.

Aunque UART se inicia con 9600, luego se establece en velocidad máxima -> UBRR = 0;

Problemas :

  1. VUSB no es estable en ambas comunicaciones basadas en interrupciones. o comunicación no basada en interrupciones.
  2. Tuve éxito en tenerlo estable solo una vez... pero los datos recibidos eran basura.

Como supero estos problemas..

hizo un pequeño protocolo para datos ..

SYNC_START XY END_SYNC

el código del transmisor:

//////////////////////////////////////////////////////////////////////////
//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);
    }
}

El código del receptor:

//////////////////////////////////////////////////////////////////////////
//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;
        }
    }
}
Dudo que el módulo UARt esté diseñado para funcionar con un divisor de velocidad en baudios de 0. Intente configurarlo en 1 o 2 al menos.
@brhans UBRR = 0 está bien. B a tu d = F o s C / ( dieciséis ( tu B R R + 1 ) )
@Akash, solo debe leer el UBRregistro una vez, no varias veces. Hay un FIFO en el bloque UART y cuando lee el registro, pasa al siguiente valor en el FIFO.
if(UDR==START_SYNC_BYTE){lee el valor y luego lo olvida. ...X=UDR;lo lee por segunda vez, lo que puede corromper el valor. Deberías hacer uint8_t in = UDR;y luegoif(in==START_SYNC_BYTE){...X=in;
En tercer lugar, ¿estás usando un cristal? Si es así, ¿es de 12 MHz? Si no, ¿ha calibrado el oscilador interno a 12,8 MHz? (puede hacer esto conectando D- a un pin de interrupción y configurando correctamente VUSB)
Sí... En realidad estaba haciendo lo que dijiste antes, pero ni siquiera funcionó... Estoy usando un cristal externo de 16 MHz... Actualizaré el código...
@TomCarpenter He editado y actualizado el código.
La otra cosa es que parece estar enviando un valor de 16 bits para X y otro para Y. Pero luego está recibiendo un valor de 8 bits para X e Y. ¿A dónde fueron los otros dos bytes?
En realidad, no me preocupa eso porque mis valores van desde... 20 a -20, así que estoy bien con eso... lo siento, no lo mencioné en la pregunta
Probablemente no relacionado, pero no debería sei()venir antes usbPoll() ?
Eso fue un error .. Código actualizado
¿Qué biblioteca UART está utilizando y qué hacen los parámetros booleanos UART_Init(9600 , false , true , false)?
Biblioteca autoescrita .. 9600 es velocidad en baudios .. 1 bool es para tx encendido .. 2 bool es para RX encendido .. 3 bool es para modo de interrupción encendido ..

Respuestas (1)

Hay un problema principal que se ha señalado en los comentarios:

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

En esta parte, está leyendo desde UDR vacío como se END_SYNC_BYTEalmacenó anteriormente, por lo que esta declaración está a punto de ser siempre falsa.

La forma menos complicada es almacenar cada byte entrante en el búfer FIFO (o incluso usar una biblioteca basada en interrupciones que pueda manejar v-usb) y procesar el mensaje completo en una sola ejecución.