1
\$\begingroup\$

I'm working UART data transfer from one ATmega8 to other while the receiver runs VUSB acting as HID Mouse to the PC.

UART though init with 9600 , later is set to max speed -> UBRR = 0;

Problems :

  1. VUSB isnt stable on both interrupt based comm. or non interrupt based comm.
  2. I was succesfull to have it stable only once .. but the data received was garbage.

How do I overcome these problems ..

made a small protocol for data ..

SYNC_START X Y END_SYNC

the transmitter code:

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

The receiver Code :

//////////////////////////////////////////////////////////////////////////
//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;
 }
 }
}
JimmyB
3,9632 gold badges20 silver badges21 bronze badges
asked Apr 18, 2016 at 14:25
\$\endgroup\$
13
  • \$\begingroup\$ I doubt that the UARt module is intended to work with a baud-rate divisor of 0. Try setting it to 1 or 2 at least. \$\endgroup\$ Commented Apr 18, 2016 at 16:30
  • \$\begingroup\$ @brhans UBRR = 0 is fine. \$Baud = Fosc/(16(UBRR+1))\$ \$\endgroup\$ Commented Apr 18, 2016 at 16:33
  • \$\begingroup\$ @Akash, you should only read the UBR register once, not multiple times. There is a FIFO on the UART block and when you read the register it moves on to the next value in the FIFO. \$\endgroup\$ Commented Apr 18, 2016 at 16:39
  • 2
    \$\begingroup\$ if(UDR==START_SYNC_BYTE){ reads the value then forgets it. ...X=UDR; reads it a second time which can corrupt the value. You should do uint8_t in = UDR; and then if(in==START_SYNC_BYTE){...X=in; \$\endgroup\$ Commented Apr 18, 2016 at 16:39
  • 1
    \$\begingroup\$ The other thing is you appear to be sending a 16bit value for X and another for Y. But then you are receiving an 8bit value for X and Y. Where did the other two bytes go? \$\endgroup\$ Commented Apr 18, 2016 at 17:41

1 Answer 1

1
\$\begingroup\$

There is one main issue that has been pointed in comments:

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

In this part you are reading from empty UDR as the END_SYNC_BYTE is stored earlier, so this statement is about to be always false.

The less complicated way is to store each incoming byte into FIFO buffer (or even use interrupt based lib that can deal with v-usb) and process entire message in one run.

answered May 17, 2016 at 20:15
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.