Communication problem
Posted: Thu Mar 01, 2012 9:19 pm
I'm working on a project using V-USB and have a problem with communication with the host (Win XP, C#). Every report ID is working except one that is not transmitted properly. That contains an uint32_t and an uint16_t. The uint32_t represents the seconds of a software RTC and the uint16_t the milliseconds of the same RTC.
When I read that report with my host application it works fine up to 429 seconds, but when the RTC reaches 430 seconds I read 0. Then it counts up to 429 again, again wrapping around to 0 and so on. The problem stays the same when I change the starting value, so I assume it's not an issue that appears when the device ran for more than 429 seconds.
On PB1 a LED is connected that shall light when 429 seconds have passed. This LED turns on as it should and stays on afterwards until I disconnect (pull the USB-plug) and reconnect the device. So I assume the content of the variable is higher than 429, but I still read 0.
Does somebody have an idea what could cause that behaviour?
Down below you can find the code which I reduced to a minimum, but the problem still remains.
When I read that report with my host application it works fine up to 429 seconds, but when the RTC reaches 430 seconds I read 0. Then it counts up to 429 again, again wrapping around to 0 and so on. The problem stays the same when I change the starting value, so I assume it's not an issue that appears when the device ran for more than 429 seconds.
On PB1 a LED is connected that shall light when 429 seconds have passed. This LED turns on as it should and stays on afterwards until I disconnect (pull the USB-plug) and reconnect the device. So I assume the content of the variable is higher than 429, but I still read 0.
Does somebody have an idea what could cause that behaviour?
Down below you can find the code which I reduced to a minimum, but the problem still remains.
Code: Select all
#include <avr/io.h>
#include <avr/wdt.h> /* watchdog */
#include <avr/interrupt.h> /* for sei() */
#include <util/delay.h> /* for _delay_ms() */
#include <string.h> /* for memcpy */
#include <avr/pgmspace.h> /* required by usbdrv.h */
#include "usbdrv.h" /* v-usb driver */
#include "configUSBIRRemoteReceiver.h" /* USB-IRRR config file */
#ifndef F_CPU
#error F_CPU unknown
#endif
#ifdef USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
#undef USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
#endif
#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 134
#define F_INTERRUPTS 10000
#define CPU_CYCLES_BETWEEN_INTERRUPTS (F_CPU/F_INTERRUPTS)
/* const for V-USB feature report ID handling */
enum ReportID {
noReport = 0,
NewIRCodeAvailable = 1,
ReadPowerOnEnabled = 2,
ReadTrainedIRCode = 3,
SetPowerOnEnabled = 4,
SetTrainedIRCode = 5,
repIRPollingTime = 6,
ReadIrmpVersion = 7,
repMinRepeats = 8,
// keep some spare report IDs for future use of USB-IRRR
repCurrentTime = 50,
repXtalFrequency = 51,
repWakeupTime = 52,
repWakeupTimeSpan = 53,
repPowerOffIRCode = 55,
};
/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */
PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x0b, 0x01, 0x00, 0x00, 0xff, // USAGE (Vendor Defined Page 1:Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x85, NewIRCodeAvailable, // REPORT_ID
0x95, 0x06, // REPORT_COUNT (6)
0x09, 0x00, // USAGE (Undefined)
0x82, 0x00, 0x01, // INPUT (Data,Ary,Abs,Buf)
0x85, ReadPowerOnEnabled, // REPORT_ID
0x95, 0x01, // REPORT_COUNT (1)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, ReadTrainedIRCode, // REPORT_ID
0x95, 0x06, // REPORT_COUNT (6)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, SetPowerOnEnabled, // REPORT_ID
0x95, 0x01, // REPORT_COUNT (1)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, SetTrainedIRCode, // REPORT_ID
0x95, 0x06, // REPORT_COUNT (6)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, repIRPollingTime, // REPORT_ID
0x95, 0x02, // REPORT_COUNT (2)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, ReadIrmpVersion, // REPORT_ID
0x95, 0x0A, // REPORT_COUNT (10) // works only when reading from device
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, repMinRepeats, // REPORT_ID
0x95, 0x01, // REPORT_COUNT (1)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, repCurrentTime, // REPORT_ID // Current date
0x95, 0x07, // REPORT_COUNT (6) // time in seconds (element 1-4) and msec (element 5&6)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, repXtalFrequency, // REPORT_ID // XTAL frequency
0x95, 0x04, // REPORT_COUNT (4) // Data format: uint32/Hz
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, repWakeupTime, // REPORT_ID // Wakeup Date and time
0x95, 0x04, // REPORT_COUNT (4) // time in seconds
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, repWakeupTimeSpan, // REPORT_ID // span of wakeup time
0x95, 0x01, // REPORT_COUNT (1)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0x85, repPowerOffIRCode, // REPORT_ID // IR code for shutting the PC down
0x95, 0x06, // REPORT_COUNT (6)
0x09, 0x00, // USAGE (Undefined)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0xc0 // END_COLLECTION
}; // don't forget to update USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH when you change this array
/* The following variables store the status of the current data transfer */
static uchar currentAddress = 0;
static uchar bytesRemaining = 0;
enum ReportID DoWriteReport = noReport;
enum ReportID DoReadReport = noReport;
/* global variables */
static uint32_t CurrentTime = 415;
static uint16_t InterruptTicks = 0; // count how often timer ISR was executed each second
static int16_t ClockDeviation = 0;
/* reply buffer should be big enough to cover also the irmp version ! */
static uchar replyBuf[16];
/* ------------------------------------------------------------------------- */
/* main functions for irmp */
/* ------------------------------------------------------------------------- */
void init_timer1 (void)
{
/* IR polling timer */
TCCR1B = (1 << WGM12) | (1 << CS10); // switch CTC Mode on, set prescaler to 1
// may adjust IR polling rate here to optimize IR receiving:
OCR1A = (F_CPU / F_INTERRUPTS) - 1; // compare value: 1/15000 of CPU frequency
// enable Timer1 for IR polling
#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) \
|| defined (__AVR_ATmega64__) || defined (__AVR_ATmega162__)
TIMSK = 1 << OCIE1A; // Timer1A ISR activate
#else
TIMSK1 = 1 << OCIE1A; // Timer1A ISR activate
#endif // __AVR...
}
/*-----------------------------------------------------------------------------------------------------------------
* init all io pins of the AVR, first all to input with pullups. then config USB and output pin
*---------------------------------------------------------------------------------------------------------------*/
void init_io(void)
{
/* USB pins */
USBOUT ^= _BV(USB_CFG_DMINUS_BIT) | _BV(USB_CFG_DPLUS_BIT); /* deactivate pull-ups on USB lines */
PORTB &= ~ (1 << PB1);
DDRB = (1 << PB1);
}
/*-----------------------------------------------------------------------------------------------------------------
* timer 1 compare handler, should be called every 1/10000 sec
*---------------------------------------------------------------------------------------------------------------*/
void TIMER1_COMPA_vect(void) __attribute__((interrupt));
void TIMER1_COMPA_vect(void)
{
static int16_t TimeError = 0; // RTC error compensation
// RTC error correction
if ( TimeError >= CPU_CYCLES_BETWEEN_INTERRUPTS ) // RTC too fast
{
//InterruptTicks += 0 // add zero ticks
TimeError -= CPU_CYCLES_BETWEEN_INTERRUPTS;
}
else if ( TimeError <= -CPU_CYCLES_BETWEEN_INTERRUPTS ) // RTC too slow
{
InterruptTicks += 2; // add two ticks
TimeError += CPU_CYCLES_BETWEEN_INTERRUPTS;
}
else
{
InterruptTicks += 1; // add one ticks
}
// compute time every second
if ( InterruptTicks >= F_INTERRUPTS ) // one second has passed
{
CurrentTime++; // add one second
TimeError += ClockDeviation; // accumulate deviation
InterruptTicks -= F_INTERRUPTS; // subtract number of interrupts per second
}
}
/* ------------------------------------------------------------------------- */
/* usbFunctionRead() is called when the host requests a chunk of data from
* the device. For more information see the documentation in usbdrv/usbdrv.h.
*/
uchar usbFunctionRead(uchar *data, uchar len)
{
if(len > bytesRemaining)
len = bytesRemaining;
if ( DoReadReport == repCurrentTime )
{
uint16_t temp;
cli(); // don't allow any interrupts here
temp = InterruptTicks / (F_INTERRUPTS / 1000); // scale InterruptTicks to msec
memcpy(&data[1], &CurrentTime, sizeof(CurrentTime)); // copy data to buffer
memcpy(&data[5], &temp, sizeof(InterruptTicks)); // copy data to buffer
sei();
}
currentAddress += len;
bytesRemaining -= len;
return len;
}
/* ------------------------------------------------------------------------- */
/* usbFunctionWrite() is called when the host sends a chunk of data to the
* device. For more information see the documentation in usbdrv/usbdrv.h.
*/
uchar usbFunctionWrite(uchar *data, uchar len)
{
if(bytesRemaining == 0)
return 1; /* end of transfer */
if(len > bytesRemaining)
len = bytesRemaining;
if ( DoWriteReport == repCurrentTime )
{
/* cli(); // don't allow any interrupts here
memcpy(&CurrentTime, &data[1], sizeof(CurrentTime)); // update CurrentTime with received data
memcpy(&InterruptTicks, &data[5], sizeof(InterruptTicks)); // update Int.Ticks with received data
InterruptTicks = InterruptTicks * (F_INTERRUPTS / 1000); // scale InterruptsTicks
sei();
*/ }
currentAddress += len;
bytesRemaining -= len;
return bytesRemaining == 0; /* return 1 if this was the last chunk */
}
/* ------------------------------------------------------------------------- */
usbMsgLen_t usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) // HID class request
{
/* ----------------------------------------------------------- GET REPORT (device -> host) -- */
if(rq->bRequest == USBRQ_HID_GET_REPORT) // wValue: ReportType (highbyte), ReportID (lowbyte)
{
usbMsgPtr = replyBuf;
memcpy(&replyBuf[0], &rq->wValue.bytes[0], sizeof(uchar)); // copy report id
if(rq->wValue.bytes[0] == repCurrentTime) /* Report: Current Time */
{
bytesRemaining = sizeof(CurrentTime) + sizeof(InterruptTicks) + sizeof(uchar);
DoReadReport = repCurrentTime;
return USB_NO_MSG;
}
}
/* ----------------------------------------------------------- SET REPORT (host -> device) -- */
else if(rq->bRequest == USBRQ_HID_SET_REPORT)
{
if(rq->wValue.bytes[0] == repCurrentTime) /* Report: Current Date */
{
/* bytesRemaining = sizeof(CurrentTime) + sizeof(InterruptTicks);
DoWriteReport = repCurrentTime;
return USB_NO_MSG;
*/ }
}
}
else
{
// ignore vendor type requests, we don't use any
}
return 0;
}
/* ------------------------------------------------------------------------- */
/* main function
*/
int main(void)
{
uchar i = 0;
wdt_disable(); // disable watchdog
init_io();
init_timer1(); // initialize timer
usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */
while(--i){ /* fake USB disconnect for > 500 ms */
_delay_ms(5);
}
usbDeviceConnect();
usbInit(); // initialize v-usb
sei(); // enable global int
for(;;) /* main event loop */
{
uint32_t temptime;
usbPoll(); // do a USB poll
cli();
temptime = CurrentTime;
sei();
if (temptime > 429)
{
PORTB |= (1 << PB1);
}
else
{
PORTB &= ~(1 << PB1);
}
_delay_ms(255);
}
return 0;
}