lm4f: Add USB bulk device example
I wrote this example to benchmark the USB driver. See the README.md for full details. Why README.md instead of just README. README.md shows up better on github, and makes it easier to browse the tree on github to search for an example. Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
This commit is contained in:
committed by
Piotr Esden-Tempski
parent
28f92cce2b
commit
7639a88928
24
examples/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/Makefile
Normal file
24
examples/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/Makefile
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
##
|
||||||
|
## This file is part of the libopencm3 project.
|
||||||
|
##
|
||||||
|
## Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||||
|
##
|
||||||
|
## This library is free software: you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
## the Free Software Foundation, either version 3 of the License, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This library is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU Lesser General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU Lesser General Public License
|
||||||
|
## along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
|
||||||
|
BINARY = usb_bulk_dev
|
||||||
|
|
||||||
|
LDSCRIPT = ../ek-lm4f120xl.ld
|
||||||
|
|
||||||
|
include ../../Makefile.include
|
||||||
61
examples/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/README.md
Normal file
61
examples/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/README.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
usb_bulk_dev
|
||||||
|
============
|
||||||
|
|
||||||
|
This example demonstrates the following:
|
||||||
|
* Setting up polled USB endpoints
|
||||||
|
* Setting up interrupt driven USB endpoints
|
||||||
|
* Using the UART as a debug tool
|
||||||
|
|
||||||
|
USB module
|
||||||
|
----------
|
||||||
|
|
||||||
|
Several USB endpoints are being set up:
|
||||||
|
* EP1 OUT - interrupt driven RX endpoint
|
||||||
|
* EP2 IN - interrupt driven TX endpoint
|
||||||
|
* EP3 OUT - polled RX endpoint
|
||||||
|
* EP4 IN - polled TX endpoint
|
||||||
|
* EP5 OUT - polled RX endpoint with unaligned buffer
|
||||||
|
* EP6 IN - polled TX endpoint with unaligned buffer
|
||||||
|
|
||||||
|
These endpoints do not transfer any meaningful data. Instead, they try to push
|
||||||
|
data in and out as fast as possible by writing it to the FIFOs or reading it
|
||||||
|
from the FIFOs.
|
||||||
|
|
||||||
|
The interrupt driven endpoints only read or write a packet during a callback
|
||||||
|
from the USB driver. Since the USB driver is run entirely from the USB ISR,
|
||||||
|
these callbacks are essentially interrupt driven.
|
||||||
|
|
||||||
|
The polled endpoints try to continuously read and write data. Even though
|
||||||
|
usbd_ep_read/write_packet is called continuously for these endpoints, the USB
|
||||||
|
driver will only write a packet to the TX FIFO if it is empty, and only read
|
||||||
|
a packet from the FIFO if one has arrived.
|
||||||
|
|
||||||
|
The endpoints with a misaligned buffer show the performance drop when the buffer
|
||||||
|
is not aligned to a 4 byte boundary. 32-bit memory accesses to the buffer are
|
||||||
|
downgraded to 8-bit accesses by the hardware.
|
||||||
|
|
||||||
|
Clock change module
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Pressing SW2 toggles the system clock between 80MHz, 57MHz, 40MHz, 30MHz, 20MHz,
|
||||||
|
and 16MHz by changing the PLL divisor.
|
||||||
|
|
||||||
|
Pressing SW1 bypasses the PLL completely, and runs off the raw 16MHz clock
|
||||||
|
provided by the external crystal oscillator.
|
||||||
|
|
||||||
|
Changing the system clock on-the-fly does not affect the USB peripheral. It is
|
||||||
|
possible to change the system clock while benchmarking the USB endpoint.
|
||||||
|
|
||||||
|
The current system clock is printed on the debug interface. This allows testing
|
||||||
|
the performance of the USB endpoints under different clocks.
|
||||||
|
|
||||||
|
Debug module
|
||||||
|
------------
|
||||||
|
|
||||||
|
printf() support is provided via UART0. The UART0 pins are connected to the
|
||||||
|
CDCACM interface on the ICDI chip, so no extra hardware is necessary to check
|
||||||
|
the debug output. Just connect the debug USB cable and use a terminal program to
|
||||||
|
open the ACM port with 921600-8N1.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
> $ picocom /dev/ttyACM0 -b921600
|
||||||
473
examples/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/usb_bulk_dev.c
Normal file
473
examples/lm4f/stellaris-ek-lm4f120xl/usb_bulk_dev/usb_bulk_dev.c
Normal file
@@ -0,0 +1,473 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the libopencm3 project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup Examples
|
||||||
|
*
|
||||||
|
* Establishes a basic USB devices with interrupt-driven and polled IN and OUT
|
||||||
|
* bulk endpoints.
|
||||||
|
*/
|
||||||
|
#include <libopencm3/lm4f/rcc.h>
|
||||||
|
#include <libopencm3/lm4f/gpio.h>
|
||||||
|
#include <libopencm3/lm4f/nvic.h>
|
||||||
|
#include <libopencm3/usb/usbd.h>
|
||||||
|
#include <libopencm3/lm4f/usb.h>
|
||||||
|
|
||||||
|
#include<stdio.h>
|
||||||
|
void uart_setup(void);
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
* = Clock control definitions
|
||||||
|
* ---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* This is how the RGB LED is connected on the stellaris launchpad */
|
||||||
|
#define RGB_PORT GPIOF
|
||||||
|
enum {
|
||||||
|
LED_R = GPIO1,
|
||||||
|
LED_G = GPIO3,
|
||||||
|
LED_B = GPIO2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is how the user switches are connected to GPIOF */
|
||||||
|
enum {
|
||||||
|
USR_SW1 = GPIO4,
|
||||||
|
USR_SW2 = GPIO0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The divisors we loop through when the user presses SW2 */
|
||||||
|
enum {
|
||||||
|
PLL_DIV_80MHZ = 5,
|
||||||
|
PLL_DIV_57MHZ = 7,
|
||||||
|
PLL_DIV_40MHZ = 10,
|
||||||
|
PLL_DIV_30MHZ = 13,
|
||||||
|
PLL_DIV_20MHZ = 20,
|
||||||
|
PLL_DIV_16MHZ = 25,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 plldiv[] = {
|
||||||
|
PLL_DIV_80MHZ,
|
||||||
|
PLL_DIV_57MHZ,
|
||||||
|
PLL_DIV_40MHZ,
|
||||||
|
PLL_DIV_30MHZ,
|
||||||
|
PLL_DIV_20MHZ,
|
||||||
|
PLL_DIV_16MHZ,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The PLL divisor we are currently on */
|
||||||
|
static size_t ipll = 0;
|
||||||
|
/* Are we bypassing the PLL, or not? */
|
||||||
|
static bool bypass = false;
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
* = USB descriptors
|
||||||
|
* ---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static const struct usb_device_descriptor dev_descr = {
|
||||||
|
.bLength = USB_DT_DEVICE_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_DEVICE,
|
||||||
|
.bcdUSB = 0x0110,
|
||||||
|
.bDeviceClass = 0xff,
|
||||||
|
.bDeviceSubClass = 0,
|
||||||
|
.bDeviceProtocol = 0,
|
||||||
|
.bMaxPacketSize0 = 64,
|
||||||
|
.idVendor = 0xc03e,
|
||||||
|
.idProduct = 0xb007,
|
||||||
|
.bcdDevice = 0x0110,
|
||||||
|
.iManufacturer = 1,
|
||||||
|
.iProduct = 2,
|
||||||
|
.iSerialNumber = 3,
|
||||||
|
.bNumConfigurations = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_endpoint_descriptor bulk_endp[] = {{
|
||||||
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
|
.bEndpointAddress = 0x01,
|
||||||
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
|
.wMaxPacketSize = 64,
|
||||||
|
.bInterval = 1,
|
||||||
|
}, {
|
||||||
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
|
.bEndpointAddress = 0x82,
|
||||||
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
|
.wMaxPacketSize = 64,
|
||||||
|
.bInterval = 1,
|
||||||
|
}, {
|
||||||
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
|
.bEndpointAddress = 0x03,
|
||||||
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
|
.wMaxPacketSize = 64,
|
||||||
|
.bInterval = 1,
|
||||||
|
}, {
|
||||||
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
|
.bEndpointAddress = 0x84,
|
||||||
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
|
.wMaxPacketSize = 64,
|
||||||
|
.bInterval = 1,
|
||||||
|
}, {
|
||||||
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
|
.bEndpointAddress = 0x05,
|
||||||
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
|
.wMaxPacketSize = 64,
|
||||||
|
.bInterval = 1,
|
||||||
|
}, {
|
||||||
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
|
.bEndpointAddress = 0x86,
|
||||||
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
|
||||||
|
.wMaxPacketSize = 64,
|
||||||
|
.bInterval = 1,
|
||||||
|
}};
|
||||||
|
|
||||||
|
static const struct usb_interface_descriptor bulk_iface[] = {{
|
||||||
|
.bLength = USB_DT_INTERFACE_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
|
.bInterfaceNumber = 0,
|
||||||
|
.bAlternateSetting = 0,
|
||||||
|
.bNumEndpoints = 6,
|
||||||
|
.bInterfaceClass = 0xff,
|
||||||
|
.bInterfaceSubClass = 0xff,
|
||||||
|
.bInterfaceProtocol = 0xff,
|
||||||
|
.iInterface = 0,
|
||||||
|
|
||||||
|
.endpoint = bulk_endp,
|
||||||
|
|
||||||
|
.extra = NULL,
|
||||||
|
.extralen = 0,
|
||||||
|
}};
|
||||||
|
|
||||||
|
static const struct usb_interface ifaces[] = {{
|
||||||
|
.num_altsetting = 1,
|
||||||
|
.altsetting = bulk_iface,
|
||||||
|
}};
|
||||||
|
|
||||||
|
static const struct usb_config_descriptor config_descr = {
|
||||||
|
.bLength = USB_DT_CONFIGURATION_SIZE,
|
||||||
|
.bDescriptorType = USB_DT_CONFIGURATION,
|
||||||
|
.wTotalLength = 0,
|
||||||
|
.bNumInterfaces = 1,
|
||||||
|
.bConfigurationValue = 1,
|
||||||
|
.iConfiguration = 0,
|
||||||
|
.bmAttributes = 0x80,
|
||||||
|
.bMaxPower = 0x32,
|
||||||
|
.interface = ifaces,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern usbd_driver lm4f_usb_driver;
|
||||||
|
static usbd_device *bulk_dev;
|
||||||
|
static u8 usbd_control_buffer[128];
|
||||||
|
static u8 config_set = 0;
|
||||||
|
|
||||||
|
static const char *usb_strings[] = {
|
||||||
|
"libopencm3",
|
||||||
|
"usb_dev_bulk",
|
||||||
|
"none",
|
||||||
|
"DEMO",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
* = USB Module
|
||||||
|
* ---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mux the USB pins to their analog function
|
||||||
|
*/
|
||||||
|
static void usb_setup(void)
|
||||||
|
{
|
||||||
|
/* USB pins are connected to port D */
|
||||||
|
periph_clock_enable(RCC_GPIOD);
|
||||||
|
/* Mux USB pins to their analog function */
|
||||||
|
gpio_mode_setup(GPIOD, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4 | GPIO5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable USB interrupts
|
||||||
|
*
|
||||||
|
* We don't enable the USB peripheral clock here, but we need it on in order to
|
||||||
|
* acces USB registers. Hence, this must be called after usbd_init().
|
||||||
|
*/
|
||||||
|
static void usb_ints_setup(void)
|
||||||
|
{
|
||||||
|
u8 usbints;
|
||||||
|
/* Gimme some interrupts */
|
||||||
|
usbints = USB_INT_RESET | USB_INT_DISCON | USB_INT_RESUME |
|
||||||
|
USB_INT_SUSPEND | USB_INT_SOF;
|
||||||
|
usb_enable_interrupts(usbints, 0xff, 0xff);
|
||||||
|
nvic_enable_irq(NVIC_USB0_IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback for the interrupt-driven OUT endpoint
|
||||||
|
*
|
||||||
|
* This gets called whenever a new OUT packet has arrived.
|
||||||
|
*/
|
||||||
|
static void bulk_rx_cb(usbd_device * usbd_dev, u8 ep)
|
||||||
|
{
|
||||||
|
char buf[64] __attribute__ ((aligned(4)));
|
||||||
|
|
||||||
|
(void)ep;
|
||||||
|
|
||||||
|
/* Read the packet to clear the FIFO and make room for a new packet */
|
||||||
|
usbd_ep_read_packet(usbd_dev, 0x01, buf, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback for the interrupt-driven IN endpoint
|
||||||
|
*
|
||||||
|
* This gets called whenever an IN packet has been successfully transmitted.
|
||||||
|
*/
|
||||||
|
static void bulk_tx_cb(usbd_device * usbd_dev, u8 ep)
|
||||||
|
{
|
||||||
|
char buf[64] __attribute__ ((aligned(4)));
|
||||||
|
|
||||||
|
(void)ep;
|
||||||
|
|
||||||
|
/* Keep sending packets */
|
||||||
|
usbd_ep_write_packet(usbd_dev, 0x82, buf, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the USB configuration
|
||||||
|
*
|
||||||
|
* Called after the host issues a SetConfiguration request.
|
||||||
|
*/
|
||||||
|
static void set_config(usbd_device * usbd_dev, u16 wValue)
|
||||||
|
{
|
||||||
|
u8 data[64] __attribute__ ((aligned(4)));
|
||||||
|
|
||||||
|
(void)wValue;
|
||||||
|
printf("Configuring endpoints.\n\r");
|
||||||
|
usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, bulk_rx_cb);
|
||||||
|
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, bulk_tx_cb);
|
||||||
|
usbd_ep_setup(usbd_dev, 0x03, USB_ENDPOINT_ATTR_BULK, 64, NULL);
|
||||||
|
usbd_ep_setup(usbd_dev, 0x84, USB_ENDPOINT_ATTR_BULK, 64, NULL);
|
||||||
|
usbd_ep_setup(usbd_dev, 0x05, USB_ENDPOINT_ATTR_BULK, 64, NULL);
|
||||||
|
usbd_ep_setup(usbd_dev, 0x86, USB_ENDPOINT_ATTR_BULK, 64, NULL);
|
||||||
|
|
||||||
|
/* The main loop will not touch the EPs until this is set */
|
||||||
|
config_set = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Bootstrap" the callback-based endpoint
|
||||||
|
* Data will stay in the FIFO until the host reads it. Once it's sent
|
||||||
|
* our callback kicks in and writes another packet in the FIFO.
|
||||||
|
*/
|
||||||
|
usbd_ep_write_packet(bulk_dev, 0x82, data, 64);
|
||||||
|
printf("Done.\n\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
* = Clock control module
|
||||||
|
* ---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the buttons and interrupts
|
||||||
|
*/
|
||||||
|
static void button_setup(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Configure GPIOF
|
||||||
|
* This port is used to control the RGB LED
|
||||||
|
*/
|
||||||
|
periph_clock_enable(RCC_GPIOF);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now take care of our buttons
|
||||||
|
*/
|
||||||
|
const u32 btnpins = USR_SW1 | USR_SW2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PF0 is a locked by default. We need to unlock it before we can
|
||||||
|
* re-purpose it as a GPIO pin.
|
||||||
|
*/
|
||||||
|
gpio_unlock_commit(GPIOF, USR_SW2);
|
||||||
|
/* Configure pins as inputs, with pull-up. */
|
||||||
|
gpio_mode_setup(GPIOF, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, btnpins);
|
||||||
|
|
||||||
|
/* Trigger interrupt on rising-edge (when button is depressed) */
|
||||||
|
gpio_configure_trigger(GPIOF, GPIO_TRIG_EDGE_RISE, btnpins);
|
||||||
|
/* Finally, Enable interrupt */
|
||||||
|
gpio_enable_interrupts(GPIOF, btnpins);
|
||||||
|
/* Enable the interrupt in the NVIC as well */
|
||||||
|
nvic_enable_irq(NVIC_GPIOF_IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
* = A main() function which does not need to do too much
|
||||||
|
* ---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
u8 data[65] __attribute__ ((aligned(4)));
|
||||||
|
|
||||||
|
gpio_enable_ahb_aperture();
|
||||||
|
rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, PLL_DIV_80MHZ);
|
||||||
|
|
||||||
|
/* We use the UART for debugging */
|
||||||
|
uart_setup();
|
||||||
|
/* And the buttons for changing the system clock on-the-fly */
|
||||||
|
button_setup();
|
||||||
|
|
||||||
|
/* Mux the GPIO pins to the USB peripheral */
|
||||||
|
usb_setup();
|
||||||
|
/* Let the stack take care of the rest */
|
||||||
|
bulk_dev = usbd_init(&lm4f_usb_driver, &dev_descr, &config_descr,
|
||||||
|
usb_strings, 4,
|
||||||
|
usbd_control_buffer, sizeof(usbd_control_buffer));
|
||||||
|
usbd_register_set_config_callback(bulk_dev, set_config);
|
||||||
|
/* Enable the interrupts. */
|
||||||
|
usb_ints_setup();
|
||||||
|
|
||||||
|
/* HALT! Don't touch the EP's until we configure them */
|
||||||
|
while (!config_set) ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For our polled endpoints, we just read and write continuously. The
|
||||||
|
* driver will only move data in or out of the FIFOs if it is safe to
|
||||||
|
* do so.
|
||||||
|
*/
|
||||||
|
while (1) {
|
||||||
|
usbd_ep_read_packet(bulk_dev, 0x03, data, 64);
|
||||||
|
usbd_ep_write_packet(bulk_dev, 0x84, data, 64);
|
||||||
|
/*
|
||||||
|
* On endpoints 5 and 6, we deliberately misalign the buffer.
|
||||||
|
* This degrades the endpoint performance.
|
||||||
|
*/
|
||||||
|
usbd_ep_read_packet(bulk_dev, 0x05, data + 1, 64);
|
||||||
|
usbd_ep_write_packet(bulk_dev, 0x86, data + 1, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Never reached */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
* = USB interrupt service routine. All the magic happens here
|
||||||
|
* ---------------------------------------------------------------------------*/
|
||||||
|
void usb0_isr(void)
|
||||||
|
{
|
||||||
|
usbd_poll(bulk_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
* = GPIO interrupt service routine. Pressing a button gets us here.
|
||||||
|
* ---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void gpiof_isr(void)
|
||||||
|
{
|
||||||
|
u8 serviced_irqs = 0;
|
||||||
|
|
||||||
|
if (gpio_is_interrupt_source(GPIOF, USR_SW1)) {
|
||||||
|
/* SW1 was just depressed */
|
||||||
|
bypass = !bypass;
|
||||||
|
if (bypass) {
|
||||||
|
rcc_pll_bypass_enable();
|
||||||
|
/*
|
||||||
|
* The divisor is still applied to the raw clock.
|
||||||
|
* Disable the divisor, or we'll divide the raw clock.
|
||||||
|
*/
|
||||||
|
SYSCTL_RCC &= ~SYSCTL_RCC_USESYSDIV;
|
||||||
|
printf("Changing system clock to 16MHz MOSC\n\r");
|
||||||
|
} else {
|
||||||
|
rcc_change_pll_divisor(plldiv[ipll]);
|
||||||
|
printf("Changing system clock to %iMHz\n\r",
|
||||||
|
400 / plldiv[ipll]);
|
||||||
|
}
|
||||||
|
/* Clear interrupt source */
|
||||||
|
serviced_irqs |= USR_SW1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpio_is_interrupt_source(GPIOF, USR_SW2)) {
|
||||||
|
/* SW2 was just depressed */
|
||||||
|
if (!bypass) {
|
||||||
|
if (plldiv[++ipll] == 0)
|
||||||
|
ipll = 0;
|
||||||
|
printf("Changing system clock to %iMHz\n\r",
|
||||||
|
400 / plldiv[ipll]);
|
||||||
|
rcc_change_pll_divisor(plldiv[ipll]);
|
||||||
|
}
|
||||||
|
/* Clear interrupt source */
|
||||||
|
serviced_irqs |= USR_SW2;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_clear_interrupt_flag(GPIOF, serviced_irqs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =============================================================================
|
||||||
|
* = Debug module
|
||||||
|
* ---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <libopencm3/lm4f/uart.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the UART
|
||||||
|
*/
|
||||||
|
void uart_setup(void)
|
||||||
|
{
|
||||||
|
/* Enable GPIOA in run mode. */
|
||||||
|
periph_clock_enable(RCC_GPIOA);
|
||||||
|
/* Configure PA0 and PA1 as alternate function pins */
|
||||||
|
gpio_set_af(GPIOA, 1, GPIO0 | GPIO1);
|
||||||
|
|
||||||
|
/* Enable the UART clock */
|
||||||
|
periph_clock_enable(RCC_UART0);
|
||||||
|
/* Slight delay before we can access the UART registers */
|
||||||
|
__asm__("nop");
|
||||||
|
__asm__("nop");
|
||||||
|
__asm__("nop");
|
||||||
|
/* Disable the UART while we mess with its setings */
|
||||||
|
uart_disable(UART0);
|
||||||
|
/* Configure the UART clock source */
|
||||||
|
uart_clock_from_piosc(UART0);
|
||||||
|
/* Set communication parameters */
|
||||||
|
uart_set_baudrate(UART0, 921600);
|
||||||
|
/* Set 8N1 */
|
||||||
|
uart_set_databits(UART0, 8);
|
||||||
|
uart_set_parity(UART0, UART_PARITY_NONE);
|
||||||
|
uart_set_stopbits(UART0, 1);
|
||||||
|
/* Enable FIFOs */
|
||||||
|
UART_LCRH(UART0) |= UART_LCRH_FEN;
|
||||||
|
/* Now that we're done messing with the settings, enable the UART */
|
||||||
|
uart_enable(UART0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write to the debug port
|
||||||
|
*
|
||||||
|
* This is called whenever printf is used. We write stdio to the UART.
|
||||||
|
*/
|
||||||
|
int _write(int file, char *ptr, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (file == 1) {
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
uart_send_blocking(UART0, ptr[i]);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user