|
|
View previous topic :: View next topic |
Author |
Message |
sinaloe
Joined: 24 Apr 2015 Posts: 3
|
some characters get lost with usb_put_packet |
Posted: Sun Apr 26, 2015 6:24 am |
|
|
Hello.
I use the ex_usb_keyboard example as basis to use my Pic 18F4550 as HID device to write into a text editor on the connected PC. The Pic is connected to a Bluetooth module which gets characters one by one.
The Pic blinks for every character as expected but once in a while a character is not written to the text editor.
Here is my header file:
Code: |
#ifndef __EX_USB_COMMON_H__
#define __EX_USB_COMMON_H__
//#define USB_ISR_POLLING
#include <18F4550.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
//leds ordered from bottom to top
#DEFINE LED1 PIN_A5 //green
#define LED2 PIN_B4 //yellow
#define LED3 PIN_A4 //red
#define STATUS_LED PIN_D7 //red
#define LEDS_OFF() LED_OFF(LED1); LED_OFF(LED2); LED_OFF(LED3); LED_OFF(STATUS_LED)
//see section below labeled USB_CABLE_IS_ATTACHED
#define PIN_USB_SENSE PIN_B0
#use rs232(baud=19200,parity=N,xmit=PIN_B3,rcv=PIN_B2,bits=8)
#ifndef LEDS_OFF
#define LEDS_OFF()
#endif
#define USB_CABLE_IS_ATTACHED() input(PIN_USB_SENSE)
#ifndef LED_ON
#define LED_ON(x) output_high(x)
#endif
#ifndef LED_OFF
#define LED_OFF(x) output_low(x)
#endif
|
And here the important parts of the source file:
Code: |
#include <bt_hid_device.h>
/////////////////////////////////////////////////////////////////////////////
//
// Include the CCS USB Libraries. See the comments at the top of these
// files for more information
//
/////////////////////////////////////////////////////////////////////////////
#include <pic18_usb.h> //Microchip PIC18Fxx5x hardware layer for usb.c
#include <usb_desc_keyboard.h> //USB Configuration and Device descriptors for this UBS device
#include <usb.c> //handles usb setup tokens and get descriptor reports
int altgr = 0;
/////////////////////////////////////////////////////////////////////////////
//
// usb_debug_task()
//
// When called periodically, displays debugging information over serial
// to display enumeration and connection states. Also lights LED2 and LED3
// based upon enumeration and connection status.
//
/////////////////////////////////////////////////////////////////////////////
void usb_debug_task(void)
{
static int8 last_connected;
static int8 last_enumerated;
int8 new_connected;
int8 new_enumerated;
new_connected=usb_attached();
new_enumerated=usb_enumerated();
if (new_connected)
LED_ON(LED2);
else
LED_OFF(LED2);
if (new_enumerated)
LED_ON(LED3);
else
LED_OFF(LED3);
last_connected=new_connected;
last_enumerated=new_enumerated;
}
typedef enum
{
KB_MODIFIER_LEFT_CTRL = 1,
KB_MODIFIER_LEFT_SHIFT = 2,
KB_MODIFIER_LEFT_ALT = 4,
KB_MODIFIER_LEFT_GUI = 8,
KB_MODIFIER_RIGHT_CTRL = 16,
KB_MODIFIER_RIGHT_SHIFT = 32,
KB_MODIFIER_RIGHT_ALT = 64, // Alt Gr
KB_MODIFIER_RIGHT_GUI = 128
} kb_modifier_t;
typedef enum
{
USB_KBD_SCANCODE_ESC = 0x29,
USB_KBD_SCANCODE_CAPS_LOC = 0x39,
USB_KBD_SCANCODE_F1 = 0x3A, //F2 is 0x3B, F3 is 0x3C, etc. this is valid up to F12
USB_KBD_SCANCODE_PRTSC = 0x46,
USB_KBD_SCANCODE_SCROLL_LOCK = 0x47,
USB_KBD_SCANCODE_PAUSE = 0x48,
USB_KBD_SCANCODE_INS = 0x49,
USB_KBD_SCANCODE_HOME = 0x4A,
USB_KBD_SCANCODE_PG_UP = 0x4B,
USB_KBD_SCANCODE_DEL = 0x4C,
USB_KBD_SCANCODE_END = 0x4D,
USB_KBD_SCANCODE_PG_DN = 0x4E,
USB_KBD_SCANCODE_RIGHT = 0x4F,
USB_KBD_SCANCODE_LEFT = 0x50,
USB_KBD_SCANCODE_DOWN = 0x51,
USB_KBD_SCANCODE_UP = 0x52,
USB_KBD_SCANCODE_NUM_LOCK = 0x53,
USB_KBD_SCANCODE_WIN_MENU = 0x65,
USB_KBD_SCANCODE_F13 = 0x68, //F14 is 0x69, F15 is 0x6A, etc. this is valid up to F24
USB_KBD_SCANCODE_HELP = 0x75,
USB_KBD_SCANCODE_UNDO = 0x7A,
USB_KBD_SCANCODE_CUT = 0x7B,
USB_KBD_SCANCODE_COPY = 0x7C,
USB_KBD_SCANCODE_PASTE = 0x7D,
USB_KBD_SCANCODE_MUTE = 0x7F,
USB_KBD_SCANCODE_VOL_UP = 0x80,
USB_KBD_SCANCODE_VOL_DOWN = 0x81
} kb_scancode_t;
unsigned int16 scancodeEN(char c)
{
unsigned int16 shift = 0;
if ((c>='A')&&(c<='Z'))
{
c = tolower(c);
shift = 0x100;
}
if ((c>='a')&&(c<='z'))
{
return(((c-='a')+4)|shift);
}
if ((c>='1')&&(c<='9'))
{
return((c-='0')+0x1D);
}
switch(c)
{
case '!': return(0x11E);
case '@': return(0x11F);
case '#': return(0x120);
case '$': return(0x121);
case '%': return(0x122);
case '^': return(0x123);
case '&': return(0x124);
case '*': return(0x125);
case '(': return(0x126);
case ')': return(0x127);
case '0': return(0x27);
case '\n': return(0x28); //enter
case '\r': return(0x28); //enter
case '\b': return(0x2A); //backspace
case '\t': return(0x2B); //tab
case ' ': return(0x2C); //space
case '_': return(0x12D);
case '-': return(0x2D);
case '+': return(0x12E);
case '=': return(0x2E);
case '{': return(0x12F);
case '[': return(0x2F);
case '}': return(0x130);
case ']': return(0x30);
case '|': return(0x131);
case '\\': return(0x31);
case ':': return(0x133);
case ';': return(0x33);
case '"': return(0x134);
case '\'': return(0x34);
case '~': return(0x135);
case '`': return(0x35);
case '<': return(0x136);
case ',': return(0x36);
case '>': return(0x137);
case '.': return(0x37);
case '?': return(0x138);
case '/': return(0x38);
}
}
unsigned int16 scancodeFR(char c)
{
...
}
unsigned int16 scancodeDE(char c)
{
...
}
void main(void)
{
unsigned int8 tx_msg[7];
unsigned int16 scancode;
//HW_INIT()
LED_ON(LED1);
LED_OFF(LED2);
LED_OFF(LED3);
usb_init_cs();
long timeout;
while (TRUE)
{
usb_task();
usb_debug_task();
if (usb_enumerated())
{
memset(tx_msg, 0x00, sizeof(tx_msg));
timeout=0;
while(!kbhit()&&(++timeout<50000));
if (kbhit())
{
LED_ON(STATUS_LED);
if(input(PIN_D4)) scancode = scancodeDE(fgetc());
if(input(PIN_D5)) scancode = scancodeEN(fgetc());
if(input(PIN_D6)) scancode = scancodeFR(fgetc());
if (bit_test(scancode, 8)) // Is bit 8 set? -> press shift
tx_msg[0] = KB_MODIFIER_LEFT_SHIFT;
if(altgr) // press Alt Gr if needed
{
tx_msg[0] = KB_MODIFIER_RIGHT_ALT;
altgr = 0;
}
tx_msg[2] = scancode;
LED_OFF(STATUS_LED);
}
usb_put_packet(1, tx_msg, sizeof(tx_msg), USB_DTS_TOGGLE);
}
}
}
|
Thanks in advance.
Best regards
Susanne |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Sun Apr 26, 2015 12:49 pm |
|
|
There is a potential problem with the way you sit and wait for kbhit.
If usb_task is not called at reasonable intervals things can/will go wrong.
To get really reliable USB, I never wait for more than a very few mSec anywhere in the code. Instead have an iinterrupt based timer for your timeout, and keep looping round the outer loop, rather than sitting in the wait.
In fact I don't see anywhere in the code, anything to increment timeout, so while waiting usb_task will never be called. Look at the warning in usb.h. |
|
|
sinaloe
Joined: 24 Apr 2015 Posts: 3
|
|
Posted: Sat May 09, 2015 2:57 am |
|
|
Hello.
I am now using now the int_rda interrupt to read the data written by my serial bluetooth module.
Code: |
#include <bt_hid_device.h>
/////////////////////////////////////////////////////////////////////////////
//
// Include the CCS USB Libraries. See the comments at the top of these
// files for more information
//
/////////////////////////////////////////////////////////////////////////////
#include <pic18_usb.h> //Microchip PIC18Fxx5x hardware layer for usb.c
#include <usb_desc_keyboard.h> //USB Configuration and Device descriptors for this UBS device
#include <usb.c> //handles usb setup tokens and get descriptor reports
int altgr = 0;
char chr=0;
unsigned int8 tx_msg[7];
/////////////////////////////////////////////////////////////////////////////
//
// usb_debug_task()
//
// When called periodically, displays debugging information over serial
// to display enumeration and connection states. Also lights LED2 and LED3
// based upon enumeration and connection status.
//
/////////////////////////////////////////////////////////////////////////////
void usb_debug_task(void)
{
static int8 last_connected;
static int8 last_enumerated;
int8 new_connected;
int8 new_enumerated;
new_connected=usb_attached();
new_enumerated=usb_enumerated();
if (new_connected)
LED_ON(LED2);
else
LED_OFF(LED2);
if (new_enumerated)
LED_ON(LED3);
else
LED_OFF(LED3);
last_connected=new_connected;
last_enumerated=new_enumerated;
}
typedef enum
{
KB_MODIFIER_LEFT_CTRL = 1,
KB_MODIFIER_LEFT_SHIFT = 2,
KB_MODIFIER_LEFT_ALT = 4,
KB_MODIFIER_LEFT_GUI = 8,
KB_MODIFIER_RIGHT_CTRL = 16,
KB_MODIFIER_RIGHT_SHIFT = 32,
KB_MODIFIER_RIGHT_ALT = 64, // Alt Gr
KB_MODIFIER_RIGHT_GUI = 128
} kb_modifier_t;
typedef enum
{
USB_KBD_SCANCODE_ESC = 0x29,
USB_KBD_SCANCODE_CAPS_LOC = 0x39,
USB_KBD_SCANCODE_F1 = 0x3A, //F2 is 0x3B, F3 is 0x3C, etc. this is valid up to F12
USB_KBD_SCANCODE_PRTSC = 0x46,
USB_KBD_SCANCODE_SCROLL_LOCK = 0x47,
USB_KBD_SCANCODE_PAUSE = 0x48,
USB_KBD_SCANCODE_INS = 0x49,
USB_KBD_SCANCODE_HOME = 0x4A,
USB_KBD_SCANCODE_PG_UP = 0x4B,
USB_KBD_SCANCODE_DEL = 0x4C,
USB_KBD_SCANCODE_END = 0x4D,
USB_KBD_SCANCODE_PG_DN = 0x4E,
USB_KBD_SCANCODE_RIGHT = 0x4F,
USB_KBD_SCANCODE_LEFT = 0x50,
USB_KBD_SCANCODE_DOWN = 0x51,
USB_KBD_SCANCODE_UP = 0x52,
USB_KBD_SCANCODE_NUM_LOCK = 0x53,
USB_KBD_SCANCODE_WIN_MENU = 0x65,
USB_KBD_SCANCODE_F13 = 0x68, //F14 is 0x69, F15 is 0x6A, etc. this is valid up to F24
USB_KBD_SCANCODE_HELP = 0x75,
USB_KBD_SCANCODE_UNDO = 0x7A,
USB_KBD_SCANCODE_CUT = 0x7B,
USB_KBD_SCANCODE_COPY = 0x7C,
USB_KBD_SCANCODE_PASTE = 0x7D,
USB_KBD_SCANCODE_MUTE = 0x7F,
USB_KBD_SCANCODE_VOL_UP = 0x80,
USB_KBD_SCANCODE_VOL_DOWN = 0x81
} kb_scancode_t;
// convert ascii character to USB HID Keyboard scancode.
// realize that there is no difference between 'A'/'a' or '1'/'!', they
// have the same scancode. in order to differentiate between these the SHIFT
// modifier has to be set (see kb_modifier_t).
// see kb_scancode_t for other scancodes that are not ascii.
// bit8 will be set if shift needs to be set (for upper case chars or '!' vs '1')
unsigned int16 scancodeEN(char c)
{
unsigned int16 shift = 0;
if ((c>='A')&&(c<='Z'))
{
c = tolower(c);
shift = 0x100;
}
if ((c>='a')&&(c<='z'))
{
return(((c-='a')+4)|shift);
}
if ((c>='1')&&(c<='9'))
{
return((c-='0')+0x1D);
}
switch(c)
{
case '[': return(0x2F);
case ')': return(0x127);
case '>': return(0x137);
case '<': return(0x136);
case '!': return(0x11E);
case '@': return(0x11F);
case '#': return(0x120);
case '$': return(0x121);
case '%': return(0x122);
case '^': return(0x123);
case '&': return(0x124);
case '*': return(0x125);
case '(': return(0x126);
case '0': return(0x27);
case '\n': return(0x28); //enter
case '\r': return(0x28); //enter
case '\b': return(0x2A); //backspace
case '\t': return(0x2B); //tab
case ' ': return(0x2C); //space
case '_': return(0x12D);
case '-': return(0x2D);
case '+': return(0x12E);
case '=': return(0x2E);
case '{': return(0x12F);
case '}': return(0x130);
case ']': return(0x30);
case '|': return(0x131);
case '\\': return(0x31);
case ':': return(0x133);
case ';': return(0x33);
case '"': return(0x134);
case '\'': return(0x34);
case '~': return(0x135);
case '`': return(0x35);
case ',': return(0x36);
case '.': return(0x37);
case '?': return(0x138);
case '/': return(0x38);
}
}
#INT_RDA
void uart_handler(void)
{
chr=getc();
}
//-
void usb_keyboard_task()
{
unsigned int16 scancode;
if (usb_tbe(1))
{
tx_msg[0] = 0x00;
tx_msg[2] = 0x00;
if (chr!=0)
{
LED_ON(STATUS_LED);
scancode = scancodeEN(chr);
if (bit_test(scancode, 8)) // Is bit 8 set? -> press shift
tx_msg[0] = KB_MODIFIER_LEFT_SHIFT;
if(altgr) // press Alt Gr if needed
{
tx_msg[0] = KB_MODIFIER_RIGHT_ALT;
altgr = 0;
}
tx_msg[2] = scancode;
LED_OFF(STATUS_LED);
}
usb_put_packet(1, tx_msg, sizeof(tx_msg), USB_DTS_TOGGLE);
chr = 0;
}
}
void main(void)
{
LED_ON(LED1);
LED_OFF(LED2);
LED_OFF(LED3);
usb_init_cs();
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
memset(tx_msg, 0x00, sizeof(tx_msg));
while (TRUE)
{
usb_task();
if (usb_enumerated())
{
usb_keyboard_task();
}
}
}
|
The header file is still the same as in my first post.
I also tried to use usb_init() to get rid of the usb_task() but I still lose characters. I reduced the speed of character sending to one character per 400ms. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Sat May 09, 2015 7:28 am |
|
|
Using usb_init, rather than init_cs, does not get rid of the need to occasionally call the task.
What it does is reduce how often this needs to happen. With cs, you really need to call it at an interval perhaps no longer then 10mSec. With the standard init, task still does some extra housekeeping, and still must occur at intervals, but the interval can be much longer.
What you have now is much better.
However there is a piece missing from your keyboard handler.
USB keyboard devices, are _required_ to receive status data from the PC. Note _required_. The PC will send this at intervals. Your task does not handle this, so the input buffer will overflow.
Look at the example keyboard handler. Note that if anything is received from the USB, it gets the packet. It just writes it into the variable 'leds' and then ignores this. You need something similar.
Other thing, move your chr=0, to the line after you convert the scancode.
Otherwise a character typed while the USB data is being written, will be lost. |
|
|
sinaloe
Joined: 24 Apr 2015 Posts: 3
|
|
Posted: Tue May 12, 2015 10:00 am |
|
|
Thanks a lot for your help! It works! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|