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 :
- VUSB isnt stable on both interrupt based comm. or non interrupt based comm.
- 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;
}
}
}
1 Answer 1
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.
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\$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 douint8_t in = UDR;
and thenif(in==START_SYNC_BYTE){...X=in;
\$\endgroup\$