|
|
View previous topic :: View next topic |
Author |
Message |
dan king
Joined: 22 Sep 2003 Posts: 119
|
SOLVED using delays with USB |
Posted: Wed Jan 15, 2014 8:07 am |
|
|
Hi Folks,
I've been using the CCS USB drivers for a while now with the PIC18f2553 boards (Bitwhacker) from Sparkfun. Mostly using CDC terminals applications without too much trouble.
I recently started working on a project where I was using the USB as a debug terminal while the serial interface conencted to a cellular module and now I'm having a lot of problems with windows failing the USB connection. Specifically, I needed to add delays to the code while waiting for serial responses from the cell module.
I know the USB_Task() routine needs to be called frequently so I replaced delay_ms routines with
Code: |
for (j=0; j<100; j++){
usb_task();
delay_ms(1);
} |
I am still getting errors from windows with this. Is there a better way to implement the delays and keep windows happy?
CCS PCH C Compiler, Version 4.074, 44415
Thanks in advance.
Last edited by dan king on Sun Jan 26, 2014 7:16 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Jan 15, 2014 9:19 am |
|
|
Run a tick.
I have delays of several thousand seconds in some parts of my code (things that happen at up to twenty four hour intervals), but everything is done using a countdown timer running from an interrupt.
My main loop sits checking the USB, a couple of serials, an I2C connection etc., all done using buffering, so nothing actually 'waits'. When I want to wait for something I load the required delay into the corresponding counter (I have one ticking at 100Hz, and one that decrements at 1Hz), and wait till it is zero.
The code in the interrupt is done as:
Code: |
int16 countdown;
#int_timerx //at whatever you want the tick to be - I typically use 100Hz
void tick(void)
{
static int8 sec_tick=99;
if (sec_tick)
{
--sec_tick;
}
else
{
sec_tick=99;
if (countdown)
--countdown;
}
}
//Then in the main code:
do
{
if (usb_attached())
{
usb_task();
if (usb_enumerated())
{
if (usb_cdc_carrier.dte_present)
{
if (usb_cdc_oldconnected==FALSE)
{
printf(usb_cdc_putc,"I/F active\n\r"); //some message
usb_cdc_oldconnected=TRUE;
}
if (usb_cdc_kbhit())
{
//Need to parse USB here
//1) request directory of data
//2) request data for a day
//3) monitor mode (output status, and NH4)
tchar=usb_cdc_getc();
parseusb(tchar);
bit_clear(sys_stat,NO_HOST); //also clear host error
timeout=70;
}
}
else
{
usb_cdc_oldconnected=FALSE;
}
}
else
{
usb_cdc_oldconnected=FALSE;
}
}
//Here need to look at serial tasks
if (bkbhit(U2RX)) { //first UART2 (controller)
tchar=bgetc(U2RX);
stimeout=70; //have character from controller
parseserial(tchar);
wdog=250;
}
//Then half a dozen other things here talking to the other UART
//SD card, I2C, couple of peripherals etc...
if (countdown==0)
{
//perform the jobs that need to occur at the interval.
//includes setting 'countdown' to the next time required.
}
}
while (TRUE);
|
Now the 'parsers', are in each case state machines that walk through tables, so return quickly.
Notice the way that the enumeration is done. This unit has the connection sense pin enabled, so will detect attached/unattached, but also uses the DTE (set by the program), so it knows when the code connection is made by the host, and can send a message at this point, or do specific 'setup' jobs.
I've got some continuous data logs that run 'unbroken' for six months plus.
Best Wishes |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Wed Jan 15, 2014 9:22 am |
|
|
ok, i'll modify my code to follow a similar format and let you know how I make out. Thanks for the sample. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Wed Jan 15, 2014 12:49 pm |
|
|
sooo, it appears that W7 is evil. I followed the suggestion and modified my code to use a step machine and timer tick counter to ensure all routines were non-blocking and I am still having very intermittent success. W7 sometimes reports issues, press the reset on the board and sometimes it starts working, .....
I then plugged the HW into an XP machine and the code operates 100% EVERY TIME.
I'm not sure what to make of this, I'm finding some of the USB ports on the W7 machine allow me to update firmware using the USB bootloader with a Microchip custom driver, but won't run the application code using the CCS CDC driver and the other USB ports can run the CCS CDC driver but not the Microchip bootloader driver ????
I'm not sure where to go from here. If anyone has experienced this and has a solution I'd love to hear it. I so miss the simple serial days. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Wed Jan 15, 2014 3:42 pm |
|
|
Sounds like you're not the original 'administrator' on the W7 machine or only have 'some' permissions enabled.
W7 guys should know...me..I'm still in XP and it will NOT do things that W98 does.....
Good news is it's NOT PIC code at fault !!!
jay |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Wed Jan 15, 2014 6:39 pm |
|
|
I've had better luck with XP than W7 but since it's a work machine I don't have a lot of say. You're correct in that I don't have full admin rights, something short of it so I'm not sure what permissions are in play here.
If anyone has any ideas, I'd love to here them. I can get by but I have to keep switching through USB ports each time I upload new code and then try to run it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Thu Jan 16, 2014 3:34 am |
|
|
Look at power management. If the system is putting the USB peripheral to sleep, the slave code, will need to be able to handle this, or disconnection will result. W7 does a lot more 'default' power management than WXP.
Right click on desktop, 'Personalise', 'Screen Saver', 'Power management', 'Change Power settings', 'Change Plan settings', 'Change advanced power settings', 'USB settings', and turn off 'USB selective suspend'.
On the comment the W98 allows things that XP doesn't, the answer is 'of course'. It is the difference between a protected mode OS, and something having no protection at all. While the latter is very flexible, in terms of producing reliable operation, the former is much better, but does require that drivers exist or are written for every piece of hardware, not allowing applications to directly do such accesses. However in fact provided you know what you are doing, and are prepared to bypass the OS protection to some extent, you can get just about any W98 program to run, by using 'allowio' (web search), which turns off the hardware protection for an application. Worth knowing if you are fiddling around with old stuff that does things like fiddling with the parallel ports etc....
Best Wishes |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Thu Jan 16, 2014 7:01 am |
|
|
Thanks for the suggestion but that didn't seem to help. The really odd thing is that both the Microchip USB driver and the CCS driver are struggling but on different USB ports connected to the laptop. I can initiate the USB bootloaded on one USB port and it enumerates fine but on a different USB port on the same laptop the same driver fails to start. I looked in the driver settings and both USB ports are loaded the same driver from the same windows folder location.
This same type of behavior happens with the CCS CDC driver. Some of the USB ports it's working on and some it isn't. The really odd thing is that none of the ports have both drivers working.
Thanks for the help. I know this isn't a windows support forum but this is really frustrating. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Sat Jan 18, 2014 9:05 am |
|
|
So a little more info as I worked with this a bit more. I have determined the issue isn't necessarily a win7 problem?? I determined this when I loaded previous usb code projects I developed and they functioned correctly with win7. I'm trying to narrow down specifics to help figure out whats going on so maybe someone will have an idea but here are some findings;
1. if I compile my current code and then load it into the micro using the USB bootloader, after a reset win7 won't recognize the device even if I press the reset. I have to physically unplug the USB connection and then it works most of the time. Something happens when switching between the USB drivers.
2. when my code has issues, the pic code is not running. I have a heartbeat LED in the TIMER code and that stops running. I am getting power to the pic though because a power LED is lit, USB powered board. A reset doesn't recover operation, requires USB to be unplugged.
3. This is the really odd one, when I have USB code loaded into the board that is acting flakey, touching the board near the programming button will lock up the IC because the heartbeat LED stops. Stable running USB code does not do this on the same board. If you look at the board layout on the sparkfun site you will see that port B is near the button, I have them configured at outputs except 1 bit being used as an input with the b pullups enabled. The button is configured as an input, schematic is located on the sparkfun site.
I will be cleaning up a simple example program to demonstrate the problem so maybe someone can review and comment but that's it for now. I'll post links to the board and schematic as well but I have to run for now.
Any thoughts and/or suggestions are welcome as I'm kind of baffled with this one.
Thanks, Dan |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Sat Jan 18, 2014 9:31 am |
|
|
sample code demonstrating the problem, links to come:
Code: |
#include <18F2550.h>
//#include <18F2553.h> //requires custom pic18_usb.h file to include 2553
#include <string.h> // to use the string functions, strstr()
#include <stdlib.h> //for using the atof function
#fuses CPUDIV1 //oscillator postscaler = PLL/2
#fuses HSPLL //HS crystal option with PLL
#fuses PLL6 //PLL postscaler div 6 for UBW ver 2.0 with 24Mhz crystal = 4Mhz to PLL input
//#fuses PLL5 //PLL postscaler div 5 for UBW ver 1.0
#fuses USBDIV
#fuses NOWDT //no wdt
#fuses NOPROTECT //no code protect
#fuses NOLVP //no Low voltage Programming
#fuses NOXINST //no extended instructions
#fuses vregen //usb voltage regulator enable
#fuses MCLR //enable external reset so bootloader can be started !!!
#fuses WRTB //disable write to boot block to protect bootloader
#fuses NOPBADEN //configure port B as digital I/O on reset
//#device adc=10
#use delay(clock=48000000)
#use standard_io(A)
#use standard_io(B)
//change to 4800 with cell
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,stream=cell, errors)
#include <usb_cdc.h>
#byte PORTA = 0xF80
#byte PORTB = 0XF81
#BYTE PORTC = 0xF82
////////////////////////////////////////////////////
// Constants and variables
#bit sysled = PORTC.1 //on UBW led c.0 and c.1 are onboard leds. C.2 = input button
#bit testled = PORTC.0
#bit button = PORTC.2
#bit Cell_on = PORTB.0 //npn used to switch the cell module on
#bit Tstat_trigger = PORTB.1 //if tstat closes, send an sms
//////////////////////////////////////
#define WORD unsigned long // Data type definitions
int16 countdown;
int heartbeat;
///////////////////////////////////////////////////////
// General prototypes //
// local prototypes
void execute_usbcmd(char);
//========================================================
// Reserve space for the bootloader and relocate reset vector and int vectors
#build(reset=0x800,interrupt=0x808)
#org 0x000, 0x7ff{}
void main(){
set_tris_c(0b10000100);
set_tris_b(0b00000010);
port_b_pullups(TRUE);
sysled = 0;
testled = 0;
usb_init_cs();
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
enable_interrupts(INT_TIMER0);
enable_interrupts(global);
//usb_cdc_putc("\r\n Cellular test program \r\n");
while(1){
usb_task();
if (usb_cdc_carrier.dte_present){ //waits for usb connection to terminal
if (usb_cdc_kbhit()) {
execute_usbcmd(usb_cdc_getc());
}
}
} //close while 1
} //close main
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
#int_timer0 //at whatever you want the tick to be - I typically use 100Hz
void tick(void)
{
static int8 sec_tick=9;
//testled = !testled;
set_timer0( get_timer0() + 6000);
if (sec_tick)
{
--sec_tick;
}
else
{
sec_tick=9; //countdown in 100 ms counts- 10hz
testled = !testled;
if (countdown)
--countdown;
}
}
///////////////////////////////////////////////////
// function interprets commands received through the usb port
void execute_usbcmd(char c){
switch (c){
case 'h': usb_cdc_putc("help usb link\n\r");
usb_cdc_putc("a - send AT to check for response\r\n");
usb_cdc_putc("p - to print cellular buffer\r\n");
usb_cdc_putc("w - what carriers are present?(long hang time, must be connected to network)\r\n");
usb_cdc_putc("s - check for service \r\n");
usb_cdc_putc("S - send SMS \r\n");
usb_cdc_putc("m - sim memory status \r\n");
usb_cdc_putc("r - read SMS location 1 \r\n");
usb_cdc_putc("D - delete SMS loc 2\r\n");
break;
default: ;
}
}
|
|
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Sat Jan 18, 2014 10:14 am |
|
|
so I commented out all of the USB stuff and for some reason I can lock up this board by touching various areas of the I/O ports to the point that the reset button does not restore function. I know this because the heartbeat led stops toggling and won't restart without power cycling.
https://www.sparkfun.com/datasheets/DevTools/PIC/UBW_Dev-v13.pdf
The sensitivity to lockup is greater when USB powered but can also happen on DC power, though not as sensitive. I don't call having these issues before and I've used quite a few of the bit whacker boards. I can replicate the problem between several different boards so it's not isolated.
I'm wondering if the issues I'm having are related, lockup and USB failure |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Sun Jan 19, 2014 7:28 am |
|
|
ok, I guess the USB problems are a mystery but can anyone explain what could cause the reset function to fail? I removed all of the USB code so the final project is only the timer running with the heartbeat LED and when I touch a certain area of the board, the led stops blinking. The reset (MCLR) doesn't restore the blinking, I have to power cycle to get the board running again.
The code is identical to the code posted but with all USB code removed. I can post the code if someone would like to see it. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sun Jan 19, 2014 7:37 am |
|
|
two possibilities come to mind...
1) static electricity...'zap' is putting PIC into 'lala' land.
2) MCLR is not MCLR anymore...could be 'magically' reprogrammed to be an I/O pin ?
hth
jay |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Sun Jan 19, 2014 9:54 am |
|
|
ESD is always a possibility but I don't think so. Sometimes I have to keep probing an area before the lockup occurs. No real chance to "charge up". Almost feels like a floating input but the portb pullups are enabled. Very odd.
Also, the MCLR isn't an I/O pin because I can reset the chip during normal operation and the part resets.
Thanks for the suggestions though |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Jan 24, 2014 3:32 am |
|
|
Just one little thought came to mind about this.
You may be stopping the master clock.
On these chips, there is much less leakage than on the older chips. If the master clock gets stopped, with the oscillator input biased to an indeterminate state (touching the clock pins could do this), it won't restart on it's own, and MCLR won't start it. The chip then sits 'dead', until power is removed/applied....
You can prevent this happening, by applying a tiny 'bias' to the clock input. A large resistor (2M2R say), between OSC1, and OSC2, provides the tiny kick needed to move the input pin out of this indeterminate state.
Best Wishes |
|
|
|
|
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
|