From c3e4c9a25c2910d2d66d52215b3406b13d5b23d5 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 29 Jun 2014 12:34:32 +0300 Subject: Add more board models --- boards/dk-tm4c129x/boot_demo_usb/boot_demo_usb.c | 821 +++++++++++++++++++++++ 1 file changed, 821 insertions(+) create mode 100644 boards/dk-tm4c129x/boot_demo_usb/boot_demo_usb.c (limited to 'boards/dk-tm4c129x/boot_demo_usb/boot_demo_usb.c') diff --git a/boards/dk-tm4c129x/boot_demo_usb/boot_demo_usb.c b/boards/dk-tm4c129x/boot_demo_usb/boot_demo_usb.c new file mode 100644 index 0000000..bef2012 --- /dev/null +++ b/boards/dk-tm4c129x/boot_demo_usb/boot_demo_usb.c @@ -0,0 +1,821 @@ +//***************************************************************************** +// +// boot_demo_usb.c - Main routines for the USB HID/DFU composite device +// example. +// +// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the DK-TM4C129X Firmware Package. +// +//***************************************************************************** + +#include +#include +#include "inc/hw_memmap.h" +#include "inc/hw_nvic.h" +#include "inc/hw_types.h" +#include "driverlib/debug.h" +#include "driverlib/rom.h" +#include "driverlib/rom_map.h" +#include "driverlib/sysctl.h" +#include "driverlib/systick.h" +#include "driverlib/usb.h" +#include "grlib/grlib.h" +#include "grlib/widget.h" +#include "usblib/usblib.h" +#include "usblib/usbhid.h" +#include "usblib/device/usbdevice.h" +#include "usblib/device/usbdhid.h" +#include "usblib/device/usbdhidmouse.h" +#include "usblib/device/usbddfu-rt.h" +#include "usblib/device/usbdcomp.h" +#include "drivers/frame.h" +#include "drivers/kentec320x240x16_ssd2119.h" +#include "drivers/pinout.h" +#include "drivers/touch.h" +#include "usb_hiddfu_structs.h" + +//***************************************************************************** +// +//! \addtogroup example_list +//!

Boot Loader USB Demo (boot_demo_usb)

+//! +//! This example application is used in conjunction with the USB boot loader in +//! ROM and turns the development board into a composite device supporting a +//! mouse via the Human Interface Device class and also publishing runtime +//! Device Firmware Upgrade (DFU) capability. Dragging a finger or stylus over +//! the touchscreen translates into mouse movement and presses on marked areas +//! at the bottom of the screen indicate mouse button press. This input is +//! used to generate messages in HID reports sent to the USB host allowing the +//! development board to control the mouse pointer on the host system. +//! +//! Since the device also publishes a DFU interface, host software such as the +//! dfuprog tool can determine that the device is capable of receiving software +//! updates over USB. The runtime DFU protocol allows such tools to signal the +//! device to switch into DFU mode and prepare to receive a new software image. +//! +//! Runtime DFU functionality requires only that the device listen for a +//! particular request (DETACH) from the host and, when this is received, +//! transfer control to the USB boot loader via the normal means to reenumerate +//! as a pure DFU device capable of uploading and downloading firmware images. +//! +//! Windows device drivers for both the runtime and DFU mode of operation can +//! be found in C:/TI/TivaWare_C_Series-x.x/windows_drivers assuming +//! you installed TivaWare in the default directory. +//! +//! To illustrate runtime DFU capability, use the dfuprog tool which +//! is part of the Tiva Windows USB Examples package (SW-USB-win-xxxx.msi) +//! Assuming this package is installed in the default location, the +//! dfuprog executable can be found in the +//! C:/Program Files/Texas Instruments/Tiva/usb_examples or +//! C:/Program Files (x86)/Texas Instruments/Tiva/usb_examples +//! directory. +//! +//! With the device connected to your PC and the device driver installed, enter +//! the following command to enumerate DFU devices: +//! +//! dfuprog -e +//! +//! This will list all DFU-capable devices found and you should see that you +//! have one or two devices available which are in ``Runtime'' mode. +//! +//! If you see two devices, it is strongly recommended that you disconnect +//! ICDI debug port from the PC, and power the board either with a 5V external +//! power brick or any usb wall charger which is not plugged in your pc. +//! This way, your PC is connected to the board only through USB OTG port. +//! The reason for this is that the ICDI chip on the board is DFU-capable +//! device as well as TM4C129X, if not careful, the firmware on the ICDI +//! chip could be accidently erased which can not restored easily. As a +//! result, debug capabilities would be lost! +//! +//! If IDCI debug port is disconnected from your PC, you should see only one +//! device from above command, and its index should be 0, and should be named +//! as ``Mouse with Device Firmware Upgrade''. +//! If for any reason that you cannot provide the power to the board without +//! connecting ICDI debug port to your PC, the above command should show two +//! devices, the second device is probably named as +//! ``In-Circuit Debug interface'', and we need to be careful not to update +//! the firmware on that device. So please take careful note of the index for +//! the device ``Mouse with Device Firmware Upgrade'', it could be 0 or 1, we +//! will need this index number for the following command. +//! Entering the following command will switch this device into DFU mode and +//! leave it ready to receive a new firmware image: +//! +//! dfuprog -i index -m +//! +//! After entering this command, you should notice that the device disconnects +//! from the USB bus and reconnects again. Running ``dfuprog -e'' a +//! second time will show that the device is now in DFU mode and ready to +//! receive downloads. At this point, either LM Flash Programmer or dfuprog +//! may be used to send a new application binary to the device. +// +//***************************************************************************** + +//***************************************************************************** +// +// The defines used with the g_ui32Commands variable. +// +//***************************************************************************** +#define TOUCH_TICK_EVENT 0x80000000 + +//***************************************************************************** +// +// The system tick timer rate. +// +//***************************************************************************** +#define SYSTICKS_PER_SECOND 50 + +//***************************************************************************** +// +// This structure defines the area of the display that is devoted to a +// mouse button. Touchscreen input in this area is translated into press and +// release messages for the given button. +// +//***************************************************************************** +typedef struct +{ + const char *pcLabel; + uint16_t ui16X; + uint16_t ui16Width; + uint8_t ui8ReportFlag; +} +tMouseButtonArea; + +//***************************************************************************** +// +// The height of the mouse button bar at the bottom of the display and the +// number of buttons it contains. +// +//***************************************************************************** +#define BUTTON_HEIGHT 30 +#define NUM_MOUSE_BUTTONS 3 + +//***************************************************************************** +// +// Definitions of the positions and labels for each of the three mouse buttons. +// +//***************************************************************************** +static tMouseButtonArea g_sMouseButtons[NUM_MOUSE_BUTTONS] = +{ + { "Button 1", 8, 101, MOUSE_REPORT_BUTTON_1 }, + { "Button 2", 109, 102, MOUSE_REPORT_BUTTON_2 }, + { "Button 3", 211, 101, MOUSE_REPORT_BUTTON_3 } +}; + +//***************************************************************************** +// +// Holds command bits used to signal the main loop to perform various tasks. +// +//***************************************************************************** +volatile uint32_t g_ui32Commands; + +//***************************************************************************** +// +// A flag used to indicate whether or not we are currently connected to the USB +// host. +// +//***************************************************************************** +volatile bool g_bConnected; + +//***************************************************************************** +// +// Global system tick counter holds elapsed time since the application started +// expressed in 100ths of a second. +// +//***************************************************************************** +volatile uint32_t g_ui32SysTickCount; + +//***************************************************************************** +// +// Holds the previous press position for the touchscreen. +// +//***************************************************************************** +static volatile int32_t g_i32ScreenStartX; +static volatile int32_t g_i32ScreenStartY; + +//***************************************************************************** +// +// Holds the current press position for the touchscreen. +// +//***************************************************************************** +static volatile int32_t g_i32ScreenX; +static volatile int32_t g_i32ScreenY; + +//***************************************************************************** +// +// Holds the current state of the touchscreen - pressed or not. +// +//***************************************************************************** +static volatile bool g_bScreenPressed; + +//***************************************************************************** +// +// Holds the current state of the push button - pressed or not. +// +//***************************************************************************** +static volatile uint8_t g_ui8Buttons; + +//***************************************************************************** +// +// This enumeration holds the various states that the mouse can be in during +// normal operation. +// +//***************************************************************************** +volatile enum +{ + // + // Unconfigured. + // + MOUSE_STATE_UNCONFIGURED, + + // + // No keys to send and not waiting on data. + // + MOUSE_STATE_IDLE, + + // + // Waiting on data to be sent out. + // + MOUSE_STATE_SENDING +} +g_eMouseState = MOUSE_STATE_UNCONFIGURED; + +//***************************************************************************** +// +// Graphics context used to show text on the display. +// +//***************************************************************************** +tContext g_sContext; + +//***************************************************************************** +// +// Flag used to tell the main loop that it's time to pass control back to the +// boot loader for an update. +// +//***************************************************************************** +volatile bool g_bUpdateSignalled; + +//***************************************************************************** +// +// The error routine that is called if the driver library encounters an error. +// +//***************************************************************************** +#ifdef DEBUG +void +__error__(char *pcFilename, uint32_t ui32Line) +{ +} +#endif + +//***************************************************************************** +// +// This function is called by the touchscreen driver whenever there is a +// change in press state or position. +// +//***************************************************************************** +static int32_t +MouseTouchHandler(uint32_t ui32Message, int32_t i32X, int32_t i32Y) +{ + uint32_t ui32Loop; + + switch(ui32Message) + { + // + // The touchscreen has been pressed. Remember where we are so that + // we can determine how far the pointer moves later. + // + case WIDGET_MSG_PTR_DOWN: + { + // + // Save the location of the pointer down event. + // + g_i32ScreenStartX = i32X; + g_i32ScreenStartY = i32Y; + g_i32ScreenX = i32X; + g_i32ScreenY = i32Y; + g_bScreenPressed = true; + + // + // Is the press within the button area? If so, determine which + // button has been pressed. + // + if(i32Y >= + (GrContextDpyHeightGet(&g_sContext) - BUTTON_HEIGHT - 8)) + { + // + // Run through the list of buttons to determine which one was + // pressed. + // + for(ui32Loop = 0; ui32Loop < NUM_MOUSE_BUTTONS; ui32Loop++) + { + if((i32X >= g_sMouseButtons[ui32Loop].ui16X) && + (i32X < (g_sMouseButtons[ui32Loop].ui16X + + g_sMouseButtons[ui32Loop].ui16Width))) + { + g_ui8Buttons |= + g_sMouseButtons[ui32Loop].ui8ReportFlag; + break; + } + } + } + break; + } + + // + // The touchscreen is no longer being pressed. + // + case WIDGET_MSG_PTR_UP: + { + g_bScreenPressed = false; + + // + // Ensure that all buttons are unpressed. + // + g_ui8Buttons = 0; + break; + } + + // + // The user is dragging his/her finger/stylus over the touchscreen. + // + case WIDGET_MSG_PTR_MOVE: + { + g_i32ScreenX = i32X; + g_i32ScreenY = i32Y; + break; + } + } + + return(0); +} + +//***************************************************************************** +// +// This is the callback from the USB DFU runtime interface driver. +// +// \param pvCBData is ignored by this function. +// \param ui32Event is one of the valid events for a DFU device. +// \param ui32MsgParam is defined by the event that occurs. +// \param pvMsgData is a pointer to data that is defined by the event that +// occurs. +// +// This function will be called to inform the application when a change occurs +// during operation as a DFU device. Currently, the only event passed to this +// callback is USBD_DFU_EVENT_DETACH which tells the recipient that they should +// pass control to the boot loader at the earliest, non-interrupt context +// point. +// +// \return This function will return 0. +// +//***************************************************************************** +uint32_t +DFUDetachCallback(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgData, + void *pvMsgData) +{ + if(ui32Event == USBD_DFU_EVENT_DETACH) + { + // + // Set the flag that the main loop uses to determine when it is time + // to transfer control back to the boot loader. Note that we + // absolutely DO NOT call USBDDFUUpdateBegin() here since we are + // currently in interrupt context and this would cause bad things to + // happen (and the boot loader to not work). + // + g_bUpdateSignalled = true; + } + + return(0); +} + +//***************************************************************************** +// +// This is the callback from the USB composite device class driver. +// +// \param pvCBData is ignored by this function. +// \param ui32Event is one of the valid events for a mouse device. +// \param ui32MsgParam is defined by the event that occurs. +// \param pvMsgData is a pointer to data that is defined by the event that +// occurs. +// +// This function will be called to inform the application when a change occurs +// during operation as a HID class USB mouse device. +// +// \return This function will return 0. +// +//***************************************************************************** +uint32_t +MouseHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgData, + void *pvMsgData) +{ + switch(ui32Event) + { + // + // The USB host has connected to and configured the device. + // + case USB_EVENT_CONNECTED: + { + g_eMouseState = MOUSE_STATE_IDLE; + g_bConnected = true; + break; + } + + // + // The USB host has disconnected from the device. + // + case USB_EVENT_DISCONNECTED: + { + g_bConnected = false; + g_eMouseState = MOUSE_STATE_UNCONFIGURED; + break; + } + + // + // A report was sent to the host. We are not free to send another. + // + case USB_EVENT_TX_COMPLETE: + { + g_eMouseState = MOUSE_STATE_IDLE; + break; + } + + } + return(0); +} + +//***************************************************************************** +// +// This function updates the display to show button state. +// +// This function is called from ButtonHandler to update the display showing +// the state of each of the buttons. +// +// Returns None. +// +//***************************************************************************** +void +UpdateDisplay(uint8_t ui8Buttons, bool bRedraw) +{ + static uint8_t ui8LastButtons; + tRectangle sRect, sRectOutline; + uint32_t ui32Loop; + + // + // Initialize the Y coordinates of the button rectangle. + // + sRectOutline.i16YMin = + GrContextDpyHeightGet(&g_sContext) - BUTTON_HEIGHT - 8; + sRectOutline.i16YMax = GrContextDpyHeightGet(&g_sContext) - 1 - 8; + sRect.i16YMin = sRectOutline.i16YMin + 1; + sRect.i16YMax = sRectOutline.i16YMax - 1; + + // + // Loop through each of the mouse buttons, drawing each in turn. + // + for(ui32Loop = 0; ui32Loop < NUM_MOUSE_BUTTONS; ui32Loop++) + { + // + // Draw the outline if we are redrawing the whole button area. + // + if(bRedraw) + { + GrContextForegroundSet(&g_sContext, ClrWhite); + + sRectOutline.i16XMin = g_sMouseButtons[ui32Loop].ui16X; + sRectOutline.i16XMax = (sRectOutline.i16XMin + + g_sMouseButtons[ui32Loop].ui16Width) - 1; + + GrRectDraw(&g_sContext, &sRectOutline); + } + + // + // Has the button state changed since we last drew it or are we + // drawing the buttons unconditionally? + // + if(((g_ui8Buttons & g_sMouseButtons[ui32Loop].ui8ReportFlag) != + (ui8LastButtons & g_sMouseButtons[ui32Loop].ui8ReportFlag)) || + bRedraw) + { + // + // Set the appropriate button color depending upon whether the + // button is pressed or not. + // + GrContextForegroundSet(&g_sContext, + ((g_ui8Buttons & + g_sMouseButtons[ui32Loop].ui8ReportFlag) ? + ClrRed : ClrGreen)); + + sRect.i16XMin = g_sMouseButtons[ui32Loop].ui16X + 1; + sRect.i16XMax = (sRect.i16XMin + + g_sMouseButtons[ui32Loop].ui16Width) - 3; + GrRectFill(&g_sContext, &sRect); + + // + // Draw the button text. + // + GrContextForegroundSet(&g_sContext, ClrWhite); + GrStringDrawCentered(&g_sContext, + g_sMouseButtons[ui32Loop].pcLabel, + -1, (sRect.i16XMin + sRect.i16XMax) / 2, + (sRect.i16YMin + sRect.i16YMax) / 2, 0); + } + } + + // + // Remember the button state we just drew. + // + ui8LastButtons = ui8Buttons; +} + +//***************************************************************************** +// +// This function handles updates due to touchscreen input. +// +// This function is called periodically from the main loop to check the +// touchscreen state and, if necessary, send a HID report back to the host +// system. +// +// Returns Returns \b true on success or \b false if an error is detected. +// +//***************************************************************************** +static void +TouchHandler(void) +{ + int32_t i32DeltaX, i32DeltaY; + static uint8_t ui8Buttons = 0; + + // + // Is someone pressing the screen or has the button changed state? If so, + // we determine how far they have dragged their finger/stylus and use this + // to calculate mouse position changes to send to the host. + // + if(g_bScreenPressed || (ui8Buttons != g_ui8Buttons)) + { + // + // Calculate how far we moved since the last time we checked. This + // rather odd layout prevents a compiler warning about undefined order + // of volatile accesses. + // + i32DeltaX = g_i32ScreenX; + i32DeltaX -= g_i32ScreenStartX; + i32DeltaY = g_i32ScreenY; + i32DeltaY -= g_i32ScreenStartY; + + // + // Reset our start position. + // + g_i32ScreenStartX = g_i32ScreenX; + g_i32ScreenStartY = g_i32ScreenY; + + // + // Was there any movement or change in button state? + // + if(i32DeltaX || i32DeltaY || (ui8Buttons != g_ui8Buttons)) + { + // + // Yes - send a report back to the host after clipping the deltas + // to the maximum we can support. + // + i32DeltaX = (i32DeltaX > 127) ? 127 : i32DeltaX; + i32DeltaX = (i32DeltaX < -128) ? -128 : i32DeltaX; + i32DeltaY = (i32DeltaY > 127) ? 127 : i32DeltaY; + i32DeltaY = (i32DeltaY < -128) ? -128 : i32DeltaY; + + // + // Remember the current button state. + // + ui8Buttons = g_ui8Buttons; + + // + // Send the report back to the host. + // + USBDHIDMouseStateChange((void *)&g_sMouseDevice, + (char)i32DeltaX, (char)i32DeltaY, + ui8Buttons); + } + + // + // Update the button portion of the display. + // + UpdateDisplay(ui8Buttons, false); + } +} + +//***************************************************************************** +// +// This is the interrupt handler for the SysTick interrupt. It is called +// periodically and updates a global tick counter then sets a flag to tell the +// main loop to check the button state. +// +//***************************************************************************** +void +SysTickHandler(void) +{ + g_ui32SysTickCount++; + g_ui32Commands |= TOUCH_TICK_EVENT; +} + +//***************************************************************************** +// +// This is the main loop that runs the application. +// +//***************************************************************************** +int +main(void) +{ + uint32_t ui32SysClock; + tRectangle sRect; + + // + // Run from the PLL at 120 MHz. + // + ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | + SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | + SYSCTL_CFG_VCO_480), 120000000); + + // + // Configure the device pins. + // + PinoutSet(); + + // + // Initialize the display driver. + // + Kentec320x240x16_SSD2119Init(ui32SysClock); + + // + // Initialize the graphics context. + // + GrContextInit(&g_sContext, &g_sKentec320x240x16_SSD2119); + + // + // Draw the application frame. + // + FrameDraw(&g_sContext, "boot-demo-usb"); + + // + // Set the system tick to fire 100 times per second. + // + ROM_SysTickPeriodSet(ui32SysClock / SYSTICKS_PER_SECOND); + ROM_SysTickIntEnable(); + ROM_SysTickEnable(); + + // + // Draw the buttons in their initial (unpressed)state. + // + UpdateDisplay(g_ui8Buttons, true); + + // + // Initialize each of the device instances that will form our composite + // USB device. + // + USBDHIDMouseCompositeInit(0, &g_sMouseDevice, + &(g_sCompDevice.psDevices[0])); + USBDDFUCompositeInit(0, &g_sDFUDevice, &(g_sCompDevice.psDevices[1])); + + // + // Pass the USB library our device information, initialize the USB + // controller and connect the device to the bus. + // + USBDCompositeInit(0, &g_sCompDevice, DESCRIPTOR_BUFFER_SIZE, + g_pui8DescriptorBuffer); + + // + // Initialize the touch screen driver. + // + TouchScreenInit(ui32SysClock); + + // + // Set the touch screen event handler. + // + TouchScreenCallbackSet(MouseTouchHandler); + + // + // Drop into the main loop. + // + while(!g_bUpdateSignalled) + { + // + // Tell the user what we are doing. + // + GrContextForegroundSet(&g_sContext, ClrWhite); + GrStringDrawCentered(&g_sContext, " Waiting for host... ", -1, 160, + 110, true); + + // + // Wait for USB configuration to complete. + // + while(!g_bConnected) + { + } + + // + // Update the status. + // + GrStringDrawCentered(&g_sContext, " Host connected... ", -1, 160, + 110, true); + + // + // Now keep processing the mouse as long as the host is connected and + // we've not been told to prepare for a firmware upgrade. + // + while(g_bConnected && !g_bUpdateSignalled) + { + // + // If it is time to check the touchscreen state then do so. + // + if(g_ui32Commands & TOUCH_TICK_EVENT) + { + g_ui32Commands &= ~TOUCH_TICK_EVENT; + TouchHandler(); + } + } + + // + // If we drop out of the previous loop, either the host has + // disconnected or a firmware upgrade has been signalled. + // + } + + // + // Tell the user what's going on. + // + sRect.i16XMin = 0; + sRect.i16YMin = 0; + sRect.i16XMax = GrContextDpyWidthGet(&g_sContext); + sRect.i16YMax = GrContextDpyHeightGet(&g_sContext); + GrContextForegroundSet(&g_sContext, ClrBlack); + GrRectFill(&g_sContext, &sRect); + GrContextForegroundSet(&g_sContext, ClrWhite); + GrStringDrawCentered(&g_sContext, " Switching to DFU mode ", -1, 160, 118, + true); + + // + // Terminate the USB device and detach from the bus. + // + USBDCDTerm(0); + + // + // Disable all interrupts. + // + ROM_IntMasterDisable(); + + // + // Disable SysTick and its interrupt. + // + ROM_SysTickIntDisable(); + ROM_SysTickDisable(); + + // + // Disable all processor interrupts. Instead of disabling them one at a + // time, a direct write to NVIC is done to disable all peripheral + // interrupts. + // + HWREG(NVIC_DIS0) = 0xffffffff; + HWREG(NVIC_DIS1) = 0xffffffff; + HWREG(NVIC_DIS2) = 0xffffffff; + HWREG(NVIC_DIS3) = 0xffffffff; + HWREG(NVIC_DIS4) = 0xffffffff; + + // + // Enable and reset the USB peripheral. + // + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0); + ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0); + ROM_USBClockEnable(USB0_BASE, 8, USB_CLOCK_INTERNAL); + + // + // Wait for about a second. + // + ROM_SysCtlDelay(ui32SysClock / 3); + + // + // Re-enable interrupts at the NVIC level. + // + ROM_IntMasterEnable(); + + // + // Call the USB boot loader. + // + ROM_UpdateUSB(0); + + // + // Should never get here, but just in case. + // + while(1) + { + } +} -- cgit v1.3.1