USB PIC and software

Status
Not open for further replies.

cipi-cips

Member level 4
Joined
Jun 30, 2008
Messages
76
Helped
2
Reputation
4
Reaction score
1
Trophy points
1,288
Visit site
Activity points
1,867
Hello

I have one little problem if anyone can help

I have manage to find Firmware and Software to control PIC via USB.

Firmware is created in Microchips C18 Compiler, and software is created in C#.
In firmware and software I can set how many USB buffers will be and it is set to 65 (fromHostToDeviceBuffer[65]) for sending and 65 for receiving.

I have 6 servo motors on six ports of PIC (18F4550) and when I send signal for each servo I am using function

fromHostToDeviceBuffer[1] //send data in buffer 1 for 1 servo
fromHostToDeviceBuffer[2] //send data in buffer 2 for 2 servo
fromHostToDeviceBuffer[3] //send data in buffer 3 for 3 servo
fromHostToDeviceBuffer[4] //send data in buffer 4 for 4 servo
fromHostToDeviceBuffer[5] //send data in buffer 5 for 5 servo

And this all works fine I can control 5 servos, but problem comes when I add 1 more servo and one more function to call

fromHostToDeviceBuffer[6] //send data in buffer 6 for 6 servo

when I add this everything stops software blocks and I cant send anything, it is like when I added one more data in one more buffer USB is getting over stacked with data and it cant operate.
All data that I send for each servo are bytes.
Do I send to much data ? Do I need to put some delay between sending each data ?
 

This is from Microchips compiler

Code:
// USBMotorController.c

// includes ///////////////////////////////////////////////////////////////////////////////////////
#include<p18f4550.h>
#include"USBFunctions.h"
#include<timers.h>
#include<delays.h>
#include <stdio.h>

// chip config ////////////////////////////////////////////////////////////////////////////////////
					// clock options, see 18F4550 data sheet figure 2-1 "clock diagram" for explanation
#pragma config PLLDIV = 5				// 20 MHz external clock / PLL prescaler value of 5 = 4 MHz required input to PLL circuit
#pragma config CPUDIV = OSC1_PLL2		// non-PLL postscale / 1 OR PLL postscale / 2 for CPU clock speed, depending on FOSC setting below
#pragma config USBDIV = 2				// USB clock source = 96 MHz PLL source / 2, (full-speed USB mode)

						// if desired, could change this line to "FOSC = HS" & "oscillator postscaler" gate would be used 
						// (not the "PLL postscaler" gate), CPU speed would be 20MHz, USB circuitry would still receive 48Mhz clock
#pragma config FOSC = HSPLL_HS			// use high-speed external osc crystal, & use PLL postscaler gate to feed CPU (CPU speed = 48 MHz)

					// now the other less confusing options . . .
#pragma config FCMEN = OFF				// fail-safe clock monitor disabled
#pragma config IESO = OFF				// internal / external osc switchover bit disabled
#pragma config PWRT = OFF				// power-up timer disabled
#pragma config BOR = OFF				// brown-out reset disabled in hardware & software
#pragma config BORV = 3					// brown-out reset voltage bits, does not matter since brown-out is disabled 
#pragma config VREGEN = ON				// USB voltage regulator enabled (If using USB, capacitor goes on pin 18 (VUSB))
#pragma config WDT = OFF				// watchdog timer disabled
#pragma config WDTPS = 32768			// watchdog timer postscale, does not matter since watchdog timer is disabled
#pragma config CCP2MX = ON				// use RC1 (pin #16) as CCP2 MUX (this is the default pin for CCP2 MUX)
#pragma config PBADEN = OFF				// RB0, RB1, RB2, RB3, & RB4 are configured as digital I/O on reset
#pragma config LPT1OSC = OFF			// disable low-power option for timer 1 (timer 1 in regular mode)
#pragma config MCLRE = OFF				// master clear disabled, pin #1 is for VPP and / or RE3 use
#pragma config STVREN = ON				// stack full/underflow will cause reset
#pragma config LVP = OFF				// single-supply ICSP disabled
#pragma config ICPRT = OFF				// in-circuit debug/programming port (ICPORT) disabled, this feature is not available on 40 pin DIP package
#pragma config XINST = OFF				// instruction set extension and indexed addressing mode disabled (this is the default setting)
#pragma config DEBUG = OFF				// background debugger disabled, RA6 & RB7 configured as general purpose I/O pins
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF			// code protection bits off
#pragma config CPB = OFF				// boot block code protection off
#pragma config CPD = OFF				// data EEPROM code protection off
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF		// write protection bits off
#pragma config WRTC = OFF				// config registers write protection off
#pragma config WRTB = OFF				// boot block is not write protected
#pragma config WRTD = OFF				// data EEPROM is not write protected
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF	// table read protection bits off
#pragma config EBTRB = OFF				// boot block table read protection off

// #defines ///////////////////////////////////////////////////////////////////////////////////////
#define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS	0x1008			// these are necessary to accommodate the special linker file,
#define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS	0x1018			// do not change these !!

#define PWM1 PORTDbits.RD7
#define PWM2 PORTDbits.RD6				// output pins
#define PWM3 PORTDbits.RD5
#define PWM4 PORTDbits.RD4
#define PWM5 PORTCbits.RC7
#define PWM6 PORTCbits.RC6



// global variables ///////////////////////////////////////////////////////////////////////////////
extern BYTE g_USBDeviceState;
extern BYTE g_fromHostToDeviceBuffer[65];
extern BYTE g_fromDeviceToHostBuffer[65];

		// format for g_fromHostToDeviceBuffer[]
		// 
		// byte - purpose
		// -------------------------------------
		//	0 - do NOT use this for data, this is initialized to zero in USBstuff.c, leave as is (part of USB protocol)
		//	1 - servo position in degrees, valid range is 0 deg. - 180 deg.
		//	2 - left DC motor, 0x00 => coast, 0x01 => forward, 0x02 => reverse, 0x03 => brake
		//	3 - right DC motor, 0x00 => coast, 0x01 => forward, 0x02 => reverse, 0x03 => brake
		//	4 - stepper direction, 0x00 => hold position, 0x01 => step clockwise, 0x02 => step counterclockwise
		//	5 - unused
		//	6 - unused
		//	7 - unused
		//	8 - usused
		//	9 - unused
		// 10 - unused
		// 11 - unused
		// 12 - unused
		// 13 - unused
		// 14 - usused
		// 15 - unused
		// 16 - unused
		// 17 - unused
		// 18 - unused
		// 19 - unused
		// 20 - usused
		// 21 - unused
		// 22 - unused
		// 23 - unused
		// 24 - unused
		// 25 - unused
		// 26 - usused
		// 27 - unused
		// 28 - unused
		// 29 - unused
		// 30 - unused
		// 31 - usused
		// 32 - unused
		// 33 - unused
		// 34 - unused
		// 35 - unused
		// 36 - unused
		// 37 - usused
		// 38 - unused
		// 39 - unused
		// 40 - unused
		// 41 - unused
		// 42 - unused
		// 43 - usused
		// 44 - unused
		// 45 - unused
		// 46 - unused
		// 47 - unused
		// 48 - unused
		// 49 - usused
		// 50 - unused
		// 51 - unused
		// 52 - unused
		// 53 - unused
		// 54 - unused
		// 55 - usused
		// 56 - unused
		// 57 - unused
		// 58 - unused
		// 59 - unused
		// 60 - unused
		// 61 - usused
		// 62 - unused
		// 63 - unused
		// 64 - unused
		
		// format for g_fromDeviceToHostBuffer[]
		// 
		// byte - purpose
		// -------------------------------------
		//	0 - do NOT use this for data, this is initialized to zero in USBstuff.c, leave as is (part of USB protocol)
		//	1 - unused
		//	2 - unused
		//	3 - unused
		//	4 - unused
		//	5 - unused
		//	6 - unused
		//	7 - unused
		//	8 - usused
		//	9 - unused
		// 10 - unused
		// 11 - unused
		// 12 - unused
		// 13 - unused
		// 14 - usused
		// 15 - unused
		// 16 - unused
		// 17 - unused
		// 18 - unused
		// 19 - unused
		// 20 - usused
		// 21 - unused
		// 22 - unused
		// 23 - unused
		// 24 - unused
		// 25 - unused
		// 26 - usused
		// 27 - unused
		// 28 - unused
		// 29 - unused
		// 30 - unused
		// 31 - usused
		// 32 - unused
		// 33 - unused
		// 34 - unused
		// 35 - unused
		// 36 - unused
		// 37 - usused
		// 38 - unused
		// 39 - unused
		// 40 - unused
		// 41 - unused
		// 42 - unused
		// 43 - usused
		// 44 - unused
		// 45 - unused
		// 46 - unused
		// 47 - unused
		// 48 - unused
		// 49 - usused
		// 50 - unused
		// 51 - unused
		// 52 - unused
		// 53 - unused
		// 54 - unused
		// 55 - usused
		// 56 - unused
		// 57 - unused
		// 58 - unused
		// 59 - unused
		// 60 - unused
		// 61 - usused
		// 62 - unused
		// 63 - unused
		// 64 - unused

// function prototypes ////////////////////////////////////////////////////////////////////////////
void highISR(void);							// interrupt prototypes
void remappedHighISR(void);					//
void yourHighPriorityISRCode(void);			//
											//
void lowISR(void);							//
void remappedLowISR(void);					//
void yourLowPriorityISRCode(void);			//
											//
extern void _startup(void);					//

void yourInit(void);
void yourTasks(void);

void servoControl(void);
void commandServoToAngle2(BYTE angle);
void commandServoToAngle3(BYTE angle);
void commandServoToAngle4(BYTE angle);
void commandServoToAngle5(BYTE angle);
void commandServoToAngle6(BYTE angle);
void commandServoToAngle1(BYTE angle);

///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma code HIGH_INTERRUPT_VECTOR = 0x08
void highISR(void) {
	_asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code

///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS
void remappedHighISR(void) {
	_asm goto yourHighPriorityISRCode _endasm
}
#pragma code

///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma interrupt yourHighPriorityISRCode
void yourHighPriorityISRCode(void) {
	
	if(PIR1bits.TMR1IF == 1) {						// if timer 1 interrupt occurred . . .
		PIR1bits.TMR1IF = 0;
		servoControl();
	}
	
} // return will be a "retfie fast"
#pragma code

///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma code LOW_INTERRUPT_VECTOR = 0x18
void lowISR(void) {
	_asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm
}
#pragma code

///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS
void remappedLowISR(void) {
	_asm goto yourLowPriorityISRCode _endasm
}
#pragma code

///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma interruptlow yourLowPriorityISRCode
void yourLowPriorityISRCode(void) {
	// check which int flag is set
	// service int
	// clear int flag
	// etc.
} // return will be a "retfie"
#pragma code

///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma code REMAPPED_RESET_VECTOR = 0x1000
void _reset(void) {
	_asm goto _startup _endasm
}
#pragma code

///////////////////////////////////////////////////////////////////////////////////////////////////
void main(void) {
	USBInit();				// in USBFunctions.c
	yourInit();				// in this file
	while(1) {

		USBTasks();			// in USBFunctions.c
		yourTasks();		// in this file
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
void yourInit(void) {
								// until we have configured timers and related functionality, turn timers off

	T1CONbits.TMR1ON = 0;			// timer 1 off

	

	
		// config output pins, pin #
	TRISDbits.TRISD7 = 0;
	TRISDbits.TRISD6 = 0;		// 10
	TRISDbits.TRISD5 = 0;
	TRISDbits.TRISD4 = 0;		// 10
	TRISCbits.TRISC7 = 0;
	TRISCbits.TRISC6 = 0;		// 10


	PWM1 = 0;	
	PWM2 = 0;
	PWM3 = 0;
	PWM4 = 0;
	PWM5 = 0;
	PWM6 = 0;
	

	
	RCONbits.IPEN = 1;				// enable priority level on interrupts
	INTCONbits.GIE = 1;		// enable high-priority interrupts
	
								// timer 1 config
	PIE1bits.TMR1IE = 1;			// enable timer 1 overflow interrupt
	IPR1bits.TMR1IP = 1;			// timer 1 overflow interrupt priority set to high
	
	T1CONbits.T1CKPS1 = 0;			// timer 1 prescale 1:2
	T1CONbits.T1CKPS0 = 1;			//
	
	T1CONbits.T1OSCEN = 0;			// turn off separate oscillator that is internal to timer 1
	T1CONbits.TMR1CS = 0;			// use internal clock to increment timer 1
								// end timer 1 config
	
	T1CONbits.TMR1ON = 1;			// timer 1 on
	
}

void yourTasks(void) {

	if(g_USBDeviceState == CONFIGURED_STATE) {
		
		receiveViaUSB();											// read into input buffer
		
		// process inputs here (check g_fromHostToDeviceBuffer[x])
		// set outputs here (set g_fromDeviceToHostBuffer[x])
		//		sendViaUSB();
										// we call the DC motor function directly,
									// note that the interrupts will call the servo and stepper functions
	}		
}

void servoControl(void) {
	
	
	if(g_USBDeviceState == CONFIGURED_STATE) {					// if USB connection . . .
		
		commandServoToAngle2(g_fromHostToDeviceBuffer[1]);		// command servo to angle specified by USB input buffer		
		commandServoToAngle3(g_fromHostToDeviceBuffer[2]);
		commandServoToAngle4(g_fromHostToDeviceBuffer[3]);
		commandServoToAngle5(g_fromHostToDeviceBuffer[4]);	
		commandServoToAngle6(g_fromHostToDeviceBuffer[5]);		
		commandServoToAngle1(g_fromHostToDeviceBuffer[6]);	
		
	} else {									// else if no USB connection . . .
											// command servo to angle specified by input pot
	}
}

void commandServoToAngle2(BYTE angle) {
	int i;
	int servo_delay;
	
	servo_delay = ((int)((float)angle*4.71));
	
							// now we begin servo pulse high, pulse times are:
							// 1.0 ms => servo at   0 deg
							// 1.5 ms => servo at  90 deg
							// 2.0 ms => servo at 180 deg

	PWM2 = 1;
			// turn RB4 on, begin pulse high
	
	for(i=-120; i<servo_delay; i++) {
		Delay10TCY();			// note TCY = 0.083333us, this call will delay 0.083333us * 10 = 0.83333us
	}
	

	PWM2 = 0;
			// turn RB4 off, end pulse high
	
}

void commandServoToAngle3(BYTE angle) {
	int i;
	int servo_delay;
	
	servo_delay = ((int)((float)angle*37.68));
	
							// now we begin servo pulse high, pulse times are:
							// 1.0 ms => servo at   0 deg
							// 1.5 ms => servo at  90 deg
							// 2.0 ms => servo at 180 deg

	PWM3 = 1;
			// turn RB4 on, begin pulse high
	
	for(i=-120; i<servo_delay; i++) {
		Delay10TCY();			// note TCY = 0.083333us, this call will delay 0.083333us * 10 = 0.83333us
	}
	

	PWM3 = 0;
			// turn RB4 off, end pulse high
	
}

void commandServoToAngle4(BYTE angle) {
	int i;
	int servo_delay;
	
	servo_delay = ((int)((float)angle*4.71));
	
							// now we begin servo pulse high, pulse times are:
							// 1.0 ms => servo at   0 deg
							// 1.5 ms => servo at  90 deg
							// 2.0 ms => servo at 180 deg

	PWM4 = 1;
			// turn RB4 on, begin pulse high
	
	for(i=-120; i<servo_delay; i++) {
		Delay10TCY();			// note TCY = 0.083333us, this call will delay 0.083333us * 10 = 0.83333us
	}
	PWM4 = 0;
			// turn RB4 off, end pulse high
	
}

void commandServoToAngle5(BYTE angle) {
	int i;
	int servo_delay;
	
	servo_delay = ((int)((float)angle*4.71));
	
							// now we begin servo pulse high, pulse times are:
							// 1.0 ms => servo at   0 deg
							// 1.5 ms => servo at  90 deg
							// 2.0 ms => servo at 180 deg

	PWM5 = 1;
			// turn RB4 on, begin pulse high
	
	for(i=-120; i<servo_delay; i++) {
		Delay10TCY();			// note TCY = 0.083333us, this call will delay 0.083333us * 10 = 0.83333us
	}
	PWM5 = 0;
			// turn RB4 off, end pulse high
	
}

void commandServoToAngle6(BYTE angle) {
	int i;
	int servo_delay;
	
	servo_delay = ((int)((float)angle*4.71));
	
							// now we begin servo pulse high, pulse times are:
							// 1.0 ms => servo at   0 deg
							// 1.5 ms => servo at  90 deg
							// 2.0 ms => servo at 180 deg

	PWM6 = 1;
			// turn RB4 on, begin pulse high
	
	for(i=-120; i<servo_delay; i++) {
		Delay10TCY();			// note TCY = 0.083333us, this call will delay 0.083333us * 10 = 0.83333us
	}
	PWM6 = 0;
			// turn RB4 off, end pulse high
	
}
void commandServoToAngle1(BYTE angle) {
	int i;
	int servo_delay;
	
	servo_delay = ((int)((float)angle*4.71));
	
							// now we begin servo pulse high, pulse times are:
							// 1.0 ms => servo at   0 deg
							// 1.5 ms => servo at  90 deg
							// 2.0 ms => servo at 180 deg

	PWM1 = 1;
			// turn RB4 on, begin pulse high
	
	for(i=-120; i<servo_delay; i++) {
		Delay10TCY();			// note TCY = 0.083333us, this call will delay 0.083333us * 10 = 0.83333us
	}
	PWM1 = 0;
			// turn RB4 off, end pulse high	
}

This is from C#

Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;


///////////////////////////////////////////////////////////////////////////////////////////////////
namespace USBMotorController {

	/////////////////////////////////////////////////////////////////////////////////////////////////
	public partial class Form1 : Form {

		// constants //////////////////////////////////////////////////////////////////////////////////
		// member variables ///////////////////////////////////////////////////////////////////////////
		public USBClass USBObject;
        int p = 0;

		///////////////////////////////////////////////////////////////////////////////////////////////
		public Form1() {
			InitializeComponent();
			USBObject = new USBClass();
            
		}

		///////////////////////////////////////////////////////////////////////////////////////////////
		private void Form1_Load(object sender, EventArgs e) {
			attemptUSBConnectionFrontEnd();						// attempt USB connection
		}

		///////////////////////////////////////////////////////////////////////////////////////////////
		private void lblInfo_Click(object sender, EventArgs e) {
			if (USBObject.connectionState == USBClass.CONNECTION_NOT_SUCCESSFUL)
			{				// verify not already connected . . .
				attemptUSBConnectionFrontEnd();														// then attempt to connect again
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////
		void attemptUSBConnectionFrontEnd()
		{
			lblInfo.Text = "connecting . . . ";

			USBObject.connectionState = USBObject.attemptUSBConnection();												// attempt to connect to USB board

			if (USBObject.connectionState == USBClass.CONNECTION_SUCCESSFUL)
			{								// if connection was successful
				lblInfo.BackColor = System.Drawing.Color.LimeGreen;
				lblInfo.Text = "connection successful";
				tmrUSB.Enabled = true;
			}
			else if (USBObject.connectionState == USBClass.CONNECTION_NOT_SUCCESSFUL)
			{		// else if connection was not successful
				lblInfo.BackColor = System.Drawing.Color.Red;
				lblInfo.Text = "connection not successful, click here to try again";
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////
		private void tmrUSB_Tick(object sender, EventArgs e) {

			//			USBObject.receiveViaUSB();

            USBObject.fromHostToDeviceBuffer[1] = (byte)tbServo.Value;
            USBObject.fromHostToDeviceBuffer[2] = (byte)trackBar1.Value;
            USBObject.fromHostToDeviceBuffer[3] = (byte)trackBar2.Value;
            USBObject.fromHostToDeviceBuffer[4] = (byte)trackBar3.Value;
            USBObject.fromHostToDeviceBuffer[5] = (byte)trackBar4.Value;
            USBObject.fromHostToDeviceBuffer[6] = (byte)trackBar5.Value;

			USBObject.sendViaUSB();
		}

        private void label1_Click(object sender, EventArgs e)
        {
            label1.Text = USBObject.fromHostToDeviceBuffer[1].ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void button2_Click(object sender, EventArgs e)
        {

        }

	}		// end class
}		// end namespace
 

Is it true that adding one more data byte stops USB device operation? I rather guess it's the call to commandServoToAngle1(), that further increases software latency and possibly exceeds the maximum allowed delay to service the USB.

The delay loops are a "rusty" method to generate servo pulses, you should better think of a solution based on hardware timers and timer interrupts. Unfortunately PIC18 hasn't 6 independent hardware PWM outputs.
 
Reactions: tpetar

    tpetar

    Points: 2
    Helpful Answer Positive Rating
thx for answer
I have made some experiments and I came out for this conclusion, maybe you will know better how to fix them.

if I send bytes like this

fromHostToDeviceBuffer[1]=255;
fromHostToDeviceBuffer[2]=255;
fromHostToDeviceBuffer[3]=105;

everything blocks just with these 3 buffers, so It seams I cant send more then 615
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…