This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linking error when using Tivaware utils functions

Other Parts Discussed in Thread: MSP430F5637

My source code:

#include <stdio.h>

/*
 * TM4C123G
 */



#include "driverlib/pin_map.h"
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "uartstdio.h"



//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif




int main(void) {

	uint32_t clock_rate;


	// System clock set to 80Mhz using the 16 Mhz external crystal (MainOscillator) using PLL
	SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
	SysCtlDelay(5);

	// Enable PortF
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	// Enable PORTA
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);


	// Setup GPIOF Pins as outputs
	GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_1);



	// ---- Setup UART0 PA0/PA1 ---- //

	GPIOPinConfigure(GPIO_PA0_U0RX);
	GPIOPinConfigure(GPIO_PA1_U0TX);

	// Enable UART0
	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
	// Use 16Mhz internal Oscillator as UART BRCLK
	UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
	// Select UART function for PA0/PA1
	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
	// Initialize the UART for console I/O.
	UARTStdioConfig(0, 115200, 16000000);
	SysCtlDelay(5);

	//-------------------------------//



	UARTprintf("Test Output \n");




	clock_rate = SysCtlClockGet();




	while(1){

		// Write to Pins
		GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0x02);

		// Delay for a bit
		SysCtlDelay(100);

		// Write to Pins
		GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0x00);

		// Delay for a bit
		SysCtlDelay(100);



	}


	
	return 0;
}

I'm using CCS version 5.4 with the TM4C123G launchpad (Tiva C). The chip is the TM4C123GH6PMI.

I started a new project (did not import an existing example which from what I've read seems to be frowned upon), but thats where I'm at.  I had problems with the tivaware driverlib and inc directories not being included in the compiler search path as well as the linker search path. After figuring out I needed to include them in properties/build/arm linker/file search paths and properties/arm compiler/include options I ran into the problem of the "driverlib.lib" file not being added to the top section ("Include library file or command file as input"). 

Question 1 is, what is this file and why are the .h, .c files for the compiler sufficient?

After straightening this out I tried to send some data out of the uart with the above code.  The only way I could get this to work is to copy the uarstdio.c and uartstdio.h files to my local project directory.  I added the utils fold to my compiler search path, but I still get the linker error described above when I didn't add the driverlib.lib file.  The problem though is that I can't find a utils.lib file to added here as I did above for driverlib problem.  Does utils not have one?  If not, how do I satisfy the need for the linker to find a library file?

  • What are the exact errors you are getting now?

    The files utils are intended to be included as part of the application, not as a separate library. So it seems like it should work

    I copy the files I want (both .h and .c) into a "utils" folder in my project, add then add "${PROJECT_LOC}" to the project's include. That way I don't have to modify them by changing the include, but I build the drvlib myself.

  • When I add the utils directory to my project and include from utils/uartstdio.h I get an error because the compiler now can't find the:

    #include "third_party/speex-1.2rc1/include/speex/speex.h"
    #include "third_party/speex-1.2rc1/include/speex/speex_header.h"

    files in the header of speexlib.c.  I don't need speexlib.c, but I still wish I could just add everything to my project as I assume you're supposed and use what I need.  I'd feel more comfortable about my project setup that way rather than deleting what the compiler can't find. 

    Also, what is the purpose of adding ${PROJECT_LOC} to the project's include?  Does that just tell the compiler to search all the files in the local project directory?

  • Another problem I've been having for a few days is timing.  Could you check out this code.  I'm just interrupting with the wide timer0 and toggling an LED and sending a message out of the UART.  This interrupt executes every 1.64mS according to my scope that is watching the toggling pin, but from my understanding the system is set to 80Mhz and the counter is set to divide by 80 million.  They function SysCtlClockGet() returns 80,000,000 when I check it in the debugger but my interrupt doesn't seem to matching up to what I expect.

    I'm using the TIVA C launchpad.

    #include <stdio.h>
    
    /*
     * TM4C123G
     */
    
    
    
    #include "driverlib/pin_map.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/uart.h"
    #include "uartstdio.h"
    #include "driverlib/timer.h"
    
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, unsigned long ulLine)
    {
    }
    #endif
    
    
    
    void
    WTimer0IntHandler(void)
    {
    	// ISR Handler code below
    
    	UARTprintf("64bit timer hit! \n");
    
    
    
    	GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, ~GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_1));
    	TimerIntClear(WTIMER0_BASE, TIMER_TIMB_TIMEOUT);
    }
    
    
    
    
    int main(void) {
    
    	uint32_t clock_rate;
    
    
    	// System clock set to 80Mhz using the 16 Mhz external crystal (MainOscillator) using PLL
    	SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
    	SysCtlDelay(5);
    
    	// Enable PortF
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    	// Enable PORTA
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    	// Enable PORTF
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    
    
    	// Setup GPIOF Pins as outputs
    	GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    	// Setup PB.1 as an output for scope
    	GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_1);
    
    
    
    	// ---- Setup UART0 PA0/PA1 ---- //
    
    	GPIOPinConfigure(GPIO_PA0_U0RX);
    	GPIOPinConfigure(GPIO_PA1_U0TX);
    
    	// Enable UART0
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    	// Use 16Mhz internal Oscillator as UART BRCLK
    	UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    	// Select UART function for PA0/PA1
    	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    	// Initialize the UART for console I/O.
    	UARTStdioConfig(0, 115200, 16000000);
    	SysCtlDelay(5);
    
    	//-------------------------------//
    
    	// -------- Setup Timer ---------//
    	// Enable Timer peripheral
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
    	// Configure WTimer0 in 64-bit mode
    	TimerConfigure(WTIMER0_BASE, TIMER_CFG_PERIODIC_UP);
    	// load timer with SysClk/100 (1mS increments)
    	TimerLoadSet64(WTIMER0_BASE, SysCtlClockGet());
    	// Enable interrupts
    	TimerIntEnable(WTIMER0_BASE, TIMER_TIMA_TIMEOUT);
    	// Register ISR
    	TimerIntRegister(WTIMER0_BASE, TIMER_A, *WTimer0IntHandler);
    	// Enable Timer0
    	TimerEnable(WTIMER0_BASE, TIMER_A);
    
    	//-------------------------------//
    
    	// Enable Global processor interrupts
    	IntMasterEnable();
    
    	// Config complete, turn on green LED
    	UARTprintf("Configuration complete! \n");
    	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00);
    	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0x00);
    	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0x00);
    
    
    
    	clock_rate = SysCtlClockGet();
    
    
    
    
    
    	while(1){
    
    		// Write to Pins
    		//GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0x02);
    
    		// Delay for a bit
    		//SysCtlDelay(100);
    
    		// Write to Pins
    		//GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0x00);
    
    		// Delay for a bit
    		//SysCtlDelay(100);
    
    
    
    	}
    
    
    	
    	return 0;
    }
    
  • I add the files into a "utils" folder in the project, but I only add the files I want. Basically if you only want uartstdio, only copy those files. Pretty sure I picked this up from the example projects.

    Here is a screenshot of my workspace that shows this:

    Also, what is the purpose of adding ${PROJECT_LOC} to the project's include?  Does that just tell the compiler to search all the files in the local project directory?

    Yep. My projects don't include C:\ti\tivaware (or whatever), but include my CCS drvlib/usblib library projects (which took some time to configure right). Otherwise #include "utils/uartstdio.h" doesn't work.

    Edit: image

  • Ok...same here then.  Thanks for the info!

  • Honestly, no idea on the timer. I'm just working on USB right now.

    I'm not an expert :-)

  • Cool...I've got USB up next after I get the peripherals down.  I've got the timer working for very large values like the clock frequency or multiples of the clock frequency, but it looks like so far I am unable to use smaller numbers.  When I load anything smaller than the clock frequency into a 64 bit timer it seems to get stuck at a period of 1.64mS.

    How is USB?  I just finished a USB project on an MSP430F5637 and switched to this because I needed more horse power.  Is the framework the same for the USB stack on these ARMs?  Can you just start with an example project and build from there off of a big switch statement like in the MSP430's?

  • I say get rid of the UART code in the timer interrupt. Or set your GPIO on the timer entrance and clear before the return so you can see how long it's taking. Also the UART_BUFFERED define changes the uartstdio implementation.


    I haven't touched the msp usb code. Pretty sure it's a different (probably higher level/more complex) api. Tivaware provides callbacks on TX and RX.

    Been working on understanding the tiva/stellaris code to go faster, which is why I came to this forum.

    Edit: remove post link and add UART_BUFFERED

  • Hey thanks for the response. I figured out what happend so I'll post my working code below for others that  may run into this. 

    #include <stdio.h>
    
    /*
     * TM4C123G
     */
    
    
    
    #include "driverlib/pin_map.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/uart.h"
    #include "uartstdio.h"
    #include "driverlib/timer.h"
    
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, unsigned long ulLine)
    {
    }
    #endif
    
    
    
    void
    WTimer0IntHandler(void)
    {
    	// ISR Handler code below
    
    	//UARTprintf("64bit timer hit! \n");
    
    
    	// Toggle Pin
    	GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, ~GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_1));
    	// Toggle LED
    	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, ~GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_2));
    
    	// Clear Interrupt Flag
    	TimerIntClear(WTIMER0_BASE, TIMER_TIMA_TIMEOUT);
    }
    
    
    
    
    int main(void) {
    
    	uint32_t clock_rate;
    
    
    	// System clock set to 80Mhz using the 16 Mhz external crystal (MainOscillator) using PLL
    	SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
    	SysCtlDelay(5);
    
    	// Enable PortF	(LEDS)
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    	// Enable PORTA	(Uart)
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    	// Enable PORTF (toggle pin)
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    
    
    	// Setup GPIOF Pins as outputs
    	GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    	// Setup PB.1 as an output for scope
    	GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_1);
    
    
    
    	// ---- Setup UART0 PA0/PA1 ---- //
    
    	GPIOPinConfigure(GPIO_PA0_U0RX);
    	GPIOPinConfigure(GPIO_PA1_U0TX);
    
    	// Enable UART0
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    	// Use 16Mhz internal Oscillator as UART BRCLK
    	UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    	// Select UART function for PA0/PA1
    	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    	// Initialize the UART for console I/O.
    	UARTStdioConfig(0, 115200, 16000000);
    	SysCtlDelay(5);
    
    	//-------------------------------//
    
    	//------ Setup Timer 64-bit -----//
    
    	// Enable Timer peripheral
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
    	// Configure WTimer0 in 64-bit mode
    	TimerConfigure(WTIMER0_BASE, TIMER_CFG_PERIODIC_UP);
    	// load timer with SysClk/100 (1mS increments)
    	TimerLoadSet64(WTIMER0_BASE, (uint64_t)SysCtlClockGet()/10);
    	// Enable interrupts
    	TimerIntEnable(WTIMER0_BASE, TIMER_TIMA_TIMEOUT);
    	// Register ISR
    	TimerIntRegister(WTIMER0_BASE, TIMER_A, *WTimer0IntHandler);
    
    	//-------------------------------//
    
    
    
    	//------ Setup Timer 32-bit -----//
    	/*
    	// Enable Timer peripheral
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
    	// Configure WTimer0 in 64-bit mode
    	TimerConfigure(WTIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP);
    	// load timer with SysClk/100 (1mS increments)
    	TimerLoadSet64(WTIMER0_BASE, (uint64_t)(SysCtlClockGet()/4000000));
    	// Enable interrupts
    	TimerIntEnable(WTIMER0_BASE, TIMER_TIMA_TIMEOUT);
    	// Register ISR
    	TimerIntRegister(WTIMER0_BASE, TIMER_A, *WTimer0IntHandler);
    	*/
    	//-------------------------------//
    
    
    
    
    
    	// Enable Global processor interrupts
    	IntMasterEnable();
    
    	// Config complete, turn on green LED
    	UARTprintf("Configuration complete! \n");
    	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00);
    	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0x04);
    	GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0x00);
    
    
    
    	clock_rate = SysCtlClockGet();
    
    	// Enable Timer0
    	TimerEnable(WTIMER0_BASE, TIMER_A);
    
    
    
    	while(1){
    
    		// Write to Pins
    		//GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0x02);
    
    		// Delay for a bit
    		//SysCtlDelay(100);
    
    		// Write to Pins
    		//GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0x00);
    
    		// Delay for a bit
    		//SysCtlDelay(100);
    
    
    
    	}
    	
    	return 0;
    }
    
    The solution was typecasting the value I load into th
    TimerLoadSet64(WTIMER0_BASE, (uint64_t)SysCtlClockGet()/10);

    The expected value for this function (for that parameter) is uint64_t and I think a uint32_t was popping out of the arithmetic operation.  I'm not 100% sure on that, but it makes sense to me.  Maybe someone with more information could elaborate on why that type cast seems to be required for proper execution.

    Yea, I spent some time reading through the USB library API and it seems pretty cool, but I am a little nervous about all the descriptors.  For the MSP430 stuff they had them all pre-defined in a datapipe example and I just changed some values.  I haven't found anything like that yet.  Part of the problem is that I haven't found an actual "data pipe" or custom hid example yet that is setup to just transfer 64 byte packets of whatever you put in them minus a header or packet ID and probably a byte count for reception.

    Also, about the UART code, it slowed me down a ton!! I got rid of that and I was able to toggle at 1Mhz.  I got rid of the blink LED line and I was able to toggle at like 850nS.  I guess the library functions take more cycles than I though because I really thought I could toggle at 10's of Mhz with the single toggle pin and interrupt flag clear instruction, but I can't.  Just a heads up there too....If you are using the API/Libraries they will slow you down and create problems in the Mhz range from what I've seen.

    Another questin: Do you have to manually reset your chip to get it to program with your latest code after you program it for a while with CCS using the debugger?  For some reason after programming this launchpad a couple times it will get stuck and not run my new code until I press the hardware reset button.  After that it loads and runs fine.



      
  • > The expected value for this function (for that parameter) is uint64_t and I think a uint32_t

    Interesting, I'll keep it in mind when I try it out.

    As for the USB library, take a look at usb_dev_bulk to see a simple use of the USBBuffer implementation. It's not that fast, but it the highest level of code. I haven't played with the HID stuff, but on the PC side they provide the windows inf to get it working and a wrapper for WinUSB to get it running easily.

    >guess the library functions take more cycles than I though because I really thought I could toggle at 10's of Mhz

    Yeah the example code is going to be slower. You might try changing the C compilers optimization options. Not sure where it starts inlining the code. No idea if the HW can get 10Mhz, but remember you've only got 8 instructions to do it in. To get there, I'd want to spend some time with the datasheet to figure out the GPIO's clock and configuration, -O levels on the compiler, the assembly output and a scope. Finding the limit of the system usually means your most of the way there to understanding it...

    Personal recommendation on toggling ports for debug/timing info is to set the pin on entrance of what you are testing and clear it on exit. That way you don't have to read the pin first as this part lets you access the pins individually. This assumes your scope is fast enough to see it and your not toggling so fast as to muddy what you are timing.

  • Robbie Valentine said:
    I started a new project (did not import an existing example which from what I've read seems to be frowned upon), but

    No one should frown on deriving a project from one of the examples.  It is definitely the easier and safer way to get going.  At some point you may want to create a project from scratch to:

    1. ensure you have a solid understanding of how and where you're pulling your requisite components, and
    2. create a development environment which is better tuned to your requirements/version control/etc.

    In general, you should not pull files from driverlib, graphics lib, or usblib.  Treat them atomically and as "black boxes" so that (in a perfect world) you can just drop in new releases.  When the next TivaWare release comes out you'll simply import the new driverlib project, build it, and all your dependent projects will benefit from the new library.

    If you miss a -DTARGET_IS or -DPART_ option you'll encounter a plethora of compiler errors and you probably won't be able to resolve ROM functions and/or reference peripheral definitions.

    Even internally, when it comes to reproducing a bug/answering a question, we'll just hack on the most suitable reference app.  No shame in that.

    Robbie Valentine said:
    I ran into the problem of the "driverlib.lib" file not being added to the top section ("Include library file or command file as input"). Question 1 is, what is this file and why are the .h, .c files for the compiler sufficient?

    driverlib.lib is the pre-compiled binary for all the .C files you find in... driverlib.  It is the core of TivaWare for LM4F and is, essentially, the source code that generates the executable bits of ROM.  You can hack on it if you want but you'll be best served as using it as-is so you don't have merge conflicts when we release a new version.

    Driverlib is a CCS project in and of itself.  It's purpose is to generate driverlib.lib.  The application ("timers" for example) compiles only the application source and wants to link against driverlib.lib.

    Robbie Valentine said:
    The only way I could get this to work is to copy the uarstdio.c and uartstdio.h files to my local project directory.

    Which is the correct thing to do, actually.  Unlike driverlib which you should treat atomically, the utils directory is "a la carte".  Copy/reference only what you need in your project.

    --Miles

  • Robbie Valentine said:
    When I load anything smaller than the clock frequency into a 64 bit timer it seems to get stuck at a period of 1.64mS.

    You've already figured out that the UARTprintf() was the problem but, for posterity's sake:

    You're printing 19 characters (\n -> \r\n) at 115,200 bps.  ~10 bits per UART "frame".
     190 bits / 115,200 bps = 0.0016493 seconds.

    UARTprintf () is a synchronous printf() function.  ie. It blocks until each character is transmitted.  It doesn't buffer the entire string.  So you were elongating your ISR.

  • Robbie Valentine said:

    TimerLoadSet64(WTIMER0_BASE, (uint64_t)SysCtlClockGet()/10);
    The expected value for this function (for that parameter) is uint64_t and I think a uint32_t was popping out of the arithmetic operation.

    SysCtlClockGet() is going to return something less than 80,000,000.  That fits well within a uint32_t so the cast here shouldn't have been necessary.  The API needs to accept a 64 bit integer because the timer match value is 64 bits wide but the compiler will promote/cast for you.

    Robbie Valentine said:
    I guess the library functions take more cycles than I though because I really thought I could toggle at 10's of Mhz with the single toggle pin and interrupt flag clear instruction, but I can't.

    Time to break out the ARM Architecture Reference manual and look at your disassembly.  You're running at 80MHz.  You can execute approximately 1 instruction per clock.  If you want to toggle a pin at 10MHz that means it can take no more than 8 clocks to do it.  Off the top of my head (and this is generous because I'm probably forgetting stuff)

    1. Push <n> regs onto stack (1 clock per push)
    2. Fetch Vector (> 1 clock since flash has wait states)
    3. preamble / stack frame prep (3-4 clocks)
    4. In the best case (no branches) you need to form some literals and write them to the peripherals.  Those sequences are at least 3-4 instructions each.
    5. exit the exception (undo 3,2,1)
    You'd be hard-pressed to get in and out of an ISR in under 50 clocks.
    To illustrate in more absolute terms, check out this Cortex-M1 based app note.  See section 4.3.  The M4F could take more clocks than that depending on how FPU context is being handled.
    1 instruction per clock.  Keep the back of a napkin around... 
    --Miles
  • Guys,

    Thank you all so much for the help.  I'm now up and running with peripherals and have learned  a ton.  With the documentation and the help in this forum I am now able to use the different peripherals and explore their functionality. 

    I've run through most of what I was interested in at this point and have moved on to studying USB.  I think I'm getting there, but it is very different from the MSP430 stack (or at least it seems that way to me).  Anyways, I do have some questions I haven't been able to figure out yet on my own. 

    I'm working on a simple hid device that can send 64 bytes to my computer and receive 64 bytes from my computer.  I'm not sending a lot of data from the host to the device (TivaC chip) so it sounds like I should just go with end point 0 as my receive endpoint for my device.  I also assume it would be easier to just use this endpoint rather than have a seperate dedicated input endpoint since I'll have to have end point 0 anyways.  Section 2.13.4 in the USB user's guide states that when receiving data on end point zero you get USBD_HID_EVENT_GET_REPORT and USBD_HID_EVENT_REPORT_SENT send to the receive callback function NOT USB_EVENT_RX_AVAILABLE.  This doesn't seem like a big deal to me as long as I can use EP0 because I won't be sending much data very often.  The part that is confusing me is what to do upon these two events and what functions in the API I could use.  Below is a quote from the guide with the pertinent statements:

    On receipt of the Get_Report request, the HID device class driver sends USBD_HID_EVENT_GET_REPORT
    to the application receive callback. The application must respond to this by returning a pointer to
    the latest version of the requested report and the size of the report in bytes.

    How do I return a pointer to the latest version of the requested report?  Do I use USBDHIDPacketRead() to do this?  I'm a little confused on what to do upon these events to "get a hold of" my incoming packet.  If anyone is familiar with this could you elaborate a bit for me?


    Second question:

    Say I start with the default hid usage page.

    //*****************************************************************************
    //
    // The report descriptor for the BIOS mouse class device.
    //
    //*****************************************************************************
    static const uint8_t g_pui8ucMouseReportDescriptor[]=
    {
    UsagePage(USB_HID_GENERIC_DESKTOP),
    Usage(USB_HID_MOUSE),
    Collection(USB_HID_APPLICATION),
    Usage(USB_HID_POINTER),
    Collection(USB_HID_PHYSICAL),
    //
    // The buttons.
    //
    UsagePage(USB_HID_BUTTONS),
    UsageMinimum(1),
    UsageMaximum(3),
    LogicalMinimum(0),
    LogicalMaximum(1),
    //
    // 3 - 1 bit values for the buttons.
    //
    ReportSize(1),
    ReportCount(3),
    Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
    USB_HID_INPUT_ABS),
    //
    // 1 - 5 bit unused constant value to fill the 8 bits.
    //
    ReportSize(5),
    ReportCount(1),
    Input(USB_HID_INPUT_CONSTANT | USB_HID_INPUT_ARRAY |
    USB_HID_INPUT_ABS),
    //
    // The X and Y axis.
    //
    UsagePage(USB_HID_GENERIC_DESKTOP),
    Usage(USB_HID_X),
    Usage(USB_HID_Y),
    LogicalMinimum(-127),
    LogicalMaximum(127),
    //
    // 2 - 8 bit Values for x and y.
    //
    ReportSize(8),
    ReportCount(2),
    Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
    USB_HID_INPUT_RELATIVE),
    EndCollection,
    EndCollection,
    };

    Since I only need to send/receive 64byte packets every time do I need to specify a usage or can I just stick something there and expect/work with 64 byte packets through out my code.  If not, would I be able to simply mod this to something like the following?

    //*****************************************************************************
    //
    // The report descriptor for 64 byte packet
    //
    //*****************************************************************************
    static const uint8_t g_pui8ucMouseReportDescriptor[]=
    {
    UsagePage(USB_HID_GENERIC_DESKTOP),
    Usage(USB_HID_MOUSE),
    Collection(USB_HID_APPLICATION),
    Usage(USB_HID_POINTER),
    Collection(USB_HID_PHYSICAL),
    
    //
    // 64, 8-bit bytes per packet
    //
    ReportSize(8),
    ReportCount(64),
    Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE |
    USB_HID_INPUT_ABS),
    
    EndCollection,
    EndCollection,
    };

    I'm just looking for a simple hid comm. link so if I don't really need the usage page stuff then I would be fine getting rid of it and just working with the correct packet size/# of bytes myself on the device and host side since I'm developing both applications.

    Thanks again,

    Rob

  • Did you make progress on this?

    I'm slowly rolling my own USB HID "datapipe" app, but it's taking me a bit longer than expected. And I haven't even looked at the PC side of things. I think the USB HID's real advantage is not having to deal with a Windows .inf file. Before I progress too much further I'll take a much closer look at the requirements for WinUSB model.

    The report descriptors take some understanding...

    I'll probably follow the MSP430's datapipe configuration and use interrupt transfers for both IN and OUT.

  • Hey stepman,

    I haven't made any progress on this.  I've been spending all my time trying to get the Tiva C keyboard example to enumerate as a custom HID device rather than a keyboard or system device.  As usually when you spend all your time working on this stuff you make some progress, but it is very slow. 

    The PC side was actually great for me because I code a lot of python so I found these hid python libraries and they work great so it didn't take me long to develop a GUI with HID support.  I'm not sure what your situation is but I'd recommend checking that out. 

    I actually developed this whole system on an MSP4305x chip and got everything up and running.  When my proto types came in I realized there just wasn't enough horse power so I ended up here.  If you can use the MSPs though they are pretty great and I feel the HID development is so much simpler because TI provides that data pipe you just customize.  The part that i'm really struggling with is not so much the HID part as much as the HID/USB Tiva libraries and framework you have to use.  It is just a lot of work to get used to so far. 

    I'm in the same boat as you regarding why I'm using HID.  It is a great way to stay driver free which is a big deal for me. 

    here is a link to the PC side software I'm using for my HID comms.

    https://pypi.python.org/pypi/pywinusb/

  • Are you using TIVA C Series TM4C123Gxxxx or another version.

    UARTPrintf is it working for you?

  • I'm using TM4C123Gxxxx and it works.  The UARTPrintf() is working too, but  it is really slow so if you are debugging or running anything fairly high speed you may run into problems.  It is only really good as an asynchronus output but there shouldn't be any precision expected in the code blocks you use statements like this in.

  • Hi !

    I'm using your code and test with putty, it's not work with UARTPrintf(), but work with UARTCharPut  , so what terminal are you using ?

  • I was using realterm.