Merge pull request #19 from jboone/master
Roll-up of USB-related changes.
This commit is contained in:
58
firmware/Makefile
Normal file
58
firmware/Makefile
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#
|
||||||
|
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
#
|
||||||
|
# This file is part of HackRF.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
TARGETS = blinky \
|
||||||
|
mixertx \
|
||||||
|
sgpio \
|
||||||
|
sgpio-rx \
|
||||||
|
simpletx \
|
||||||
|
startup \
|
||||||
|
startup_systick \
|
||||||
|
startup_systick_perfo \
|
||||||
|
usb_performance
|
||||||
|
|
||||||
|
# blinky_rom_to_ram
|
||||||
|
# sgpio_passthrough_rom_to_ram
|
||||||
|
# startup_systick_perfo_rom_to_ram
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
build: examples
|
||||||
|
|
||||||
|
examples:
|
||||||
|
$(Q)for i in $(TARGETS); do \
|
||||||
|
if [ -d $$i ]; then \
|
||||||
|
printf " BUILD $$i\n"; \
|
||||||
|
$(MAKE) -C $$i || exit $?; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(Q)for i in $(addprefix lib/,$(TARGETS)) \
|
||||||
|
$(TARGETS); do \
|
||||||
|
if [ -d $$i ]; then \
|
||||||
|
printf " CLEAN $$i\n"; \
|
||||||
|
$(MAKE) -C $$i clean || exit $?; \
|
||||||
|
fi; \
|
||||||
|
done
|
||||||
|
|
||||||
|
.PHONY: build examples
|
@ -1,7 +1,30 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#
|
||||||
|
# Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
|
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
#
|
||||||
|
# This file is part of HackRF.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
BINARY = blinky
|
BINARY = blinky
|
||||||
|
|
||||||
SRC = $(BINARY).c
|
SRC = $(BINARY).c \
|
||||||
|
../common/hackrf_core.c \
|
||||||
|
../common/si5351c.c
|
||||||
|
|
||||||
include ../common/Makefile_inc.mk
|
include ../common/Makefile_inc.mk
|
||||||
|
@ -24,43 +24,12 @@
|
|||||||
|
|
||||||
#include "hackrf_core.h"
|
#include "hackrf_core.h"
|
||||||
|
|
||||||
void gpio_setup(void)
|
|
||||||
{
|
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_BOOT0, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_BOOT1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_BOOT2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_BOOT3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */
|
|
||||||
GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1|PIN_LED2|PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 boot0, boot1, boot2, boot3;
|
u32 boot0, boot1, boot2, boot3;
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
gpio_setup();
|
pin_setup();
|
||||||
|
|
||||||
/* Set 1V8 */
|
/* Set 1V8 */
|
||||||
gpio_set(PORT_EN1V8, PIN_EN1V8);
|
gpio_set(PORT_EN1V8, PIN_EN1V8);
|
||||||
|
@ -1,8 +1,31 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#
|
||||||
|
# Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
|
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
#
|
||||||
|
# This file is part of HackRF.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
BINARY = blinky
|
BINARY = blinky
|
||||||
|
|
||||||
SRC = $(BINARY).c
|
SRC = $(BINARY).c \
|
||||||
|
../common/hackrf_core.c \
|
||||||
|
../common/si5351c.c
|
||||||
|
|
||||||
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
|
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
|
||||||
include ../common/Makefile_inc.mk
|
include ../common/Makefile_inc.mk
|
||||||
|
@ -24,43 +24,12 @@
|
|||||||
|
|
||||||
#include "hackrf_core.h"
|
#include "hackrf_core.h"
|
||||||
|
|
||||||
void gpio_setup(void)
|
|
||||||
{
|
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_BOOT0, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_BOOT1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_BOOT2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_BOOT3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */
|
|
||||||
GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1|PIN_LED2|PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 boot0, boot1, boot2, boot3;
|
u32 boot0, boot1, boot2, boot3;
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
gpio_setup();
|
pin_setup();
|
||||||
|
|
||||||
/* Set 1V8 */
|
/* Set 1V8 */
|
||||||
gpio_set(PORT_EN1V8, PIN_EN1V8);
|
gpio_set(PORT_EN1V8, PIN_EN1V8);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
*
|
*
|
||||||
* This file is part of HackRF
|
* This file is part of HackRF
|
||||||
*
|
*
|
||||||
@ -25,8 +26,15 @@ MEMORY
|
|||||||
{
|
{
|
||||||
/* rom is really the shadow region that points to SPI flash or elsewhere */
|
/* rom is really the shadow region that points to SPI flash or elsewhere */
|
||||||
rom (rx) : ORIGIN = 0x00000000, LENGTH = 1M
|
rom (rx) : ORIGIN = 0x00000000, LENGTH = 1M
|
||||||
ram (rwx) : ORIGIN = 0x10000000, LENGTH = 128K
|
ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 128K
|
||||||
|
ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 72K
|
||||||
/* there are some additional RAM regions */
|
/* there are some additional RAM regions */
|
||||||
|
ram_ahb1 (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
|
||||||
|
/* Removed 32K of AHB SRAM for USB buffer. Straddles two blocks of RAM
|
||||||
|
* to get performance benefit of having two USB buffers addressable
|
||||||
|
* simultaneously (on two different buses of the AHB multilayer matrix)
|
||||||
|
*/
|
||||||
|
ram_ahb2 (rwx) : ORIGIN = 0x2000C000, LENGTH = 16K
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Include the common ld script. */
|
/* Include the common ld script. */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
|
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
*
|
*
|
||||||
* This file is part of HackRF
|
* This file is part of HackRF
|
||||||
*
|
*
|
||||||
@ -28,9 +29,14 @@ MEMORY
|
|||||||
rom_flash (rx) : ORIGIN = 0x80000000, LENGTH = 1M
|
rom_flash (rx) : ORIGIN = 0x80000000, LENGTH = 1M
|
||||||
/* rom is really the shadow region that points to SPI flash or elsewhere */
|
/* rom is really the shadow region that points to SPI flash or elsewhere */
|
||||||
rom (rx) : ORIGIN = 0x00000000, LENGTH = 1M
|
rom (rx) : ORIGIN = 0x00000000, LENGTH = 1M
|
||||||
ram (rwx) : ORIGIN = 0x10000000, LENGTH = 128K
|
ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 128K
|
||||||
/* there are some additional RAM regions for data */
|
ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 72K
|
||||||
ram_data (rw) : ORIGIN = 0x10080000, LENGTH = 72K
|
ram_ahb1 (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
|
||||||
|
/* Removed 32K of AHB SRAM for USB buffer. Straddles two blocks of RAM
|
||||||
|
* to get performance benefit of having two USB buffers addressable
|
||||||
|
* simultaneously (on two different buses of the AHB multilayer matrix)
|
||||||
|
*/
|
||||||
|
ram_ahb2 (rwx) : ORIGIN = 0x2000C000, LENGTH = 16K
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Include the common ld script. */
|
/* Include the common ld script. */
|
||||||
|
38
firmware/common/LPC4330_M4_ram_only.ld
Normal file
38
firmware/common/LPC4330_M4_ram_only.ld
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* This file is part of HackRF
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Linker script for HackRF Jellybean (LPC4330, 1M SPI flash, 264K SRAM). */
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 128K
|
||||||
|
ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 72K
|
||||||
|
ram_ahb1 (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
|
||||||
|
/* Removed 32K of AHB SRAM for USB buffer. Straddles two blocks of RAM
|
||||||
|
* to get performance benefit of having two USB buffers addressable
|
||||||
|
* simultaneously (on two different buses of the AHB multilayer matrix)
|
||||||
|
*/
|
||||||
|
ram_ahb2 (rwx) : ORIGIN = 0x2000C000, LENGTH = 16K
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Include the common ld script. */
|
||||||
|
INCLUDE libopencm3_lpc43xx_ram_only.ld
|
@ -4,6 +4,7 @@
|
|||||||
# Copyright 2010 Piotr Esden-Tempski <piotr@esden.net>
|
# Copyright 2010 Piotr Esden-Tempski <piotr@esden.net>
|
||||||
# Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
# Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
# Copyright 2012 Benjamin Vernoux <titanmkd@gmail.com>
|
# Copyright 2012 Benjamin Vernoux <titanmkd@gmail.com>
|
||||||
|
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
#
|
#
|
||||||
# This file is part of HackRF.
|
# This file is part of HackRF.
|
||||||
#
|
#
|
||||||
@ -45,12 +46,13 @@ OBJDUMP = $(PREFIX)-objdump
|
|||||||
GDB = $(PREFIX)-gdb
|
GDB = $(PREFIX)-gdb
|
||||||
TOOLCHAIN_DIR := $(shell dirname `which $(CC)`)/../$(PREFIX)
|
TOOLCHAIN_DIR := $(shell dirname `which $(CC)`)/../$(PREFIX)
|
||||||
|
|
||||||
CFLAGS += -std=c99 -O2 -g3 -Wall -Wextra -I$(LIBOPENCM3)/include -I../common \
|
CFLAGS += -std=c99 -Os -g3 -Wall -Wextra -I$(LIBOPENCM3)/include -I../common \
|
||||||
-fno-common -mcpu=cortex-m4 -mthumb -MD \
|
-fno-common -mcpu=cortex-m4 -mthumb -MD \
|
||||||
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
||||||
$(HACKRF_OPTS)
|
$(HACKRF_OPTS)
|
||||||
#LDSCRIPT ?= $(BINARY).ld
|
#LDSCRIPT ?= $(BINARY).ld
|
||||||
LDFLAGS += -L$(TOOLCHAIN_DIR)/lib/armv7e-m/fpu \
|
LDFLAGS += -L$(TOOLCHAIN_DIR)/lib/armv7e-m/fpu \
|
||||||
|
-L../common \
|
||||||
-L$(LIBOPENCM3)/lib -L$(LIBOPENCM3)/lib/lpc43xx \
|
-L$(LIBOPENCM3)/lib -L$(LIBOPENCM3)/lib/lpc43xx \
|
||||||
-T$(LDSCRIPT) -nostartfiles \
|
-T$(LDSCRIPT) -nostartfiles \
|
||||||
-Wl,--gc-sections -Xlinker -Map=$(BINARY).map
|
-Wl,--gc-sections -Xlinker -Map=$(BINARY).map
|
||||||
|
45
firmware/common/bitband.c
Normal file
45
firmware/common/bitband.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bitband.h"
|
||||||
|
|
||||||
|
volatile uint32_t* peripheral_bitband_address(volatile void* const address, const uint_fast8_t bit_number) {
|
||||||
|
const uint32_t bit_band_base = 0x42000000;
|
||||||
|
const uint32_t byte_offset = (uint32_t)address - 0x40000000;
|
||||||
|
const uint32_t bit_word_offset = (byte_offset * 32) + (bit_number * 4);
|
||||||
|
const uint32_t bit_word_address = bit_band_base + bit_word_offset;
|
||||||
|
return (volatile uint32_t*)bit_word_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void peripheral_bitband_set(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
|
||||||
|
volatile uint32_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
|
||||||
|
*bitband_address = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void peripheral_bitband_clear(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
|
||||||
|
volatile uint32_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
|
||||||
|
*bitband_address = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t peripheral_bitband_get(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
|
||||||
|
volatile uint32_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
|
||||||
|
return *bitband_address;
|
||||||
|
}
|
32
firmware/common/bitband.h
Normal file
32
firmware/common/bitband.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BITBAND_H__
|
||||||
|
#define __BITBAND_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
volatile uint32_t* peripheral_bitband_address(volatile void* const address, const uint_fast8_t bit_number);
|
||||||
|
void peripheral_bitband_set(volatile void* const peripheral_address, const uint_fast8_t bit_number);
|
||||||
|
void peripheral_bitband_clear(volatile void* const peripheral_address, const uint_fast8_t bit_number);
|
||||||
|
uint32_t peripheral_bitband_get(volatile void* const peripheral_address, const uint_fast8_t bit_number);
|
||||||
|
|
||||||
|
#endif//__BITBAND_H__
|
69
firmware/common/fault_handler.c
Normal file
69
firmware/common/fault_handler.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "fault_handler.h"
|
||||||
|
|
||||||
|
__attribute__((naked))
|
||||||
|
void hard_fault_handler(void) {
|
||||||
|
__asm__("TST LR, #4");
|
||||||
|
__asm__("ITE EQ");
|
||||||
|
__asm__("MRSEQ R0, MSP");
|
||||||
|
__asm__("MRSNE R0, PSP");
|
||||||
|
__asm__("B hard_fault_handler_c");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hard_fault_handler_c(uint32_t* args) {
|
||||||
|
(void)args;
|
||||||
|
// args[0-7]: r0, r1, r2, r3, r12, lr, pc, psr
|
||||||
|
// Other interesting registers to examine:
|
||||||
|
// CFSR: Configurable Fault Status Register
|
||||||
|
// HFSR: Hard Fault Status Register
|
||||||
|
// DFSR: Debug Fault Status Register
|
||||||
|
// AFSR: Auxiliary Fault Status Register
|
||||||
|
// MMAR: MemManage Fault Address Register
|
||||||
|
// BFAR: Bus Fault Address Register
|
||||||
|
|
||||||
|
/*
|
||||||
|
if( SCB->HFSR & SCB_HFSR_FORCED ) {
|
||||||
|
if( SCB->CFSR & SCB_CFSR_BFSR_BFARVALID ) {
|
||||||
|
SCB->BFAR;
|
||||||
|
if( SCB->CFSR & CSCB_CFSR_BFSR_PRECISERR ) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_manage_handler() {
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bus_fault_handler() {
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage_fault_handler() {
|
||||||
|
while(1);
|
||||||
|
}
|
73
firmware/common/fault_handler.h
Normal file
73
firmware/common/fault_handler.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FAULT_HANDLER__
|
||||||
|
#define __FAULT_HANDLER__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libopencm3/cm3/memorymap.h>
|
||||||
|
|
||||||
|
// TODO: Move all this to a Cortex-M(?) include file, since these
|
||||||
|
// structures are supposedly the same between processors (to an
|
||||||
|
// undetermined extent).
|
||||||
|
typedef struct armv7m_scb_t armv7m_scb_t;
|
||||||
|
struct armv7m_scb_t {
|
||||||
|
volatile const uint32_t CPUID;
|
||||||
|
volatile uint32_t ICSR;
|
||||||
|
volatile uint32_t VTOR;
|
||||||
|
volatile uint32_t AIRCR;
|
||||||
|
volatile uint32_t SCR;
|
||||||
|
volatile uint32_t CCR;
|
||||||
|
volatile uint32_t SHPR1;
|
||||||
|
volatile uint32_t SHPR2;
|
||||||
|
volatile uint32_t SHPR3;
|
||||||
|
volatile uint32_t SHCSR;
|
||||||
|
volatile uint32_t CFSR;
|
||||||
|
volatile uint32_t HFSR;
|
||||||
|
volatile uint32_t DFSR;
|
||||||
|
volatile uint32_t MMFAR;
|
||||||
|
volatile uint32_t BFAR;
|
||||||
|
volatile uint32_t AFSR;
|
||||||
|
volatile const uint32_t ID_PFR0;
|
||||||
|
volatile const uint32_t ID_PFR1;
|
||||||
|
volatile const uint32_t ID_DFR0;
|
||||||
|
volatile const uint32_t ID_AFR0;
|
||||||
|
volatile const uint32_t ID_MMFR0;
|
||||||
|
volatile const uint32_t ID_MMFR1;
|
||||||
|
volatile const uint32_t ID_MMFR2;
|
||||||
|
volatile const uint32_t ID_MMFR3;
|
||||||
|
volatile const uint32_t ID_ISAR0;
|
||||||
|
volatile const uint32_t ID_ISAR1;
|
||||||
|
volatile const uint32_t ID_ISAR2;
|
||||||
|
volatile const uint32_t ID_ISAR3;
|
||||||
|
volatile const uint32_t ID_ISAR4;
|
||||||
|
volatile const uint32_t __reserved_0x74_0x87[5];
|
||||||
|
volatile uint32_t CPACR;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
static armv7m_scb_t* const SCB = (armv7m_scb_t*)SCB_BASE;
|
||||||
|
|
||||||
|
#define SCB_HFSR_DEBUGEVT (1 << 31)
|
||||||
|
#define SCB_HFSR_FORCED (1 << 30)
|
||||||
|
#define SCB_HFSR_VECTTBL (1 << 1)
|
||||||
|
|
||||||
|
#endif//__FAULT_HANDLER__
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Michael Ossmann
|
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
* Copyright 2012 Jared Boone
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
*
|
*
|
||||||
* This file is part of HackRF.
|
* This file is part of HackRF.
|
||||||
*
|
*
|
||||||
@ -53,9 +53,9 @@ void cpu_clock_init(void)
|
|||||||
/*
|
/*
|
||||||
* Jellybean/Lemondrop clocks:
|
* Jellybean/Lemondrop clocks:
|
||||||
* CLK0 -> MAX2837
|
* CLK0 -> MAX2837
|
||||||
* CLK1 -> MAX5864/CPLD
|
* CLK1 -> MAX5864/CPLD.GCLK0
|
||||||
* CLK2 -> CPLD
|
* CLK2 -> CPLD.GCLK1
|
||||||
* CLK3 -> CPLD
|
* CLK3 -> CPLD.GCLK2
|
||||||
* CLK4 -> LPC4330
|
* CLK4 -> LPC4330
|
||||||
* CLK5 -> RFFC5072
|
* CLK5 -> RFFC5072
|
||||||
* CLK6 -> extra
|
* CLK6 -> extra
|
||||||
@ -142,51 +142,46 @@ void cpu_clock_init(void)
|
|||||||
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE;
|
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE;
|
||||||
|
|
||||||
/* use XTAL_OSC as clock source for BASE_M4_CLK (CPU) */
|
/* use XTAL_OSC as clock source for BASE_M4_CLK (CPU) */
|
||||||
CGU_BASE_M4_CLK = ((CGU_SRC_XTAL << CGU_BASE_CLK_SEL_SHIFT));
|
CGU_BASE_M4_CLK = CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_XTAL);
|
||||||
|
|
||||||
/* use XTAL_OSC as clock source for APB1 */
|
/* use XTAL_OSC as clock source for APB1 */
|
||||||
CGU_BASE_APB1_CLK = (CGU_BASE_CLK_AUTOBLOCK
|
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK
|
||||||
| (CGU_SRC_XTAL << CGU_BASE_CLK_SEL_SHIFT));
|
| CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL);
|
||||||
|
|
||||||
/* use XTAL_OSC as clock source for PLL1 */
|
/* use XTAL_OSC as clock source for PLL1 */
|
||||||
CGU_PLL1_CTRL = (CGU_PLL1_CTRL_AUTOBLOCK
|
/* Start PLL1 at 12MHz * 17 / 2 = 102MHz. */
|
||||||
| (CGU_SRC_XTAL << CGU_PLL1_CTRL_CLK_SEL_SHIFT));
|
CGU_PLL1_CTRL = CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL)
|
||||||
|
| CGU_PLL1_CTRL_PSEL(1)
|
||||||
/* configure PLL1 to produce 204 MHz clock from 12 MHz XTAL_OSC */
|
| CGU_PLL1_CTRL_NSEL(0)
|
||||||
/* not sure why, but it doesn't work without the following line */
|
| CGU_PLL1_CTRL_MSEL(16)
|
||||||
CGU_PLL1_CTRL &= ~(CGU_PLL1_CTRL_BYPASS
|
| CGU_PLL1_CTRL_PD;
|
||||||
| CGU_PLL1_CTRL_FBSEL
|
|
||||||
| CGU_PLL1_CTRL_DIRECT
|
|
||||||
| CGU_PLL1_CTRL_DIRECT
|
|
||||||
| (0x3 << CGU_PLL1_CTRL_PSEL_SHIFT)
|
|
||||||
| (0x3 << CGU_PLL1_CTRL_NSEL_SHIFT)
|
|
||||||
| (0xFF << CGU_PLL1_CTRL_MSEL_SHIFT));
|
|
||||||
CGU_PLL1_CTRL |= (CGU_PLL1_CTRL_FBSEL
|
|
||||||
| CGU_PLL1_CTRL_DIRECT
|
|
||||||
| (0 << CGU_PLL1_CTRL_PSEL_SHIFT)
|
|
||||||
| (0 << CGU_PLL1_CTRL_NSEL_SHIFT)
|
|
||||||
| (16 << CGU_PLL1_CTRL_MSEL_SHIFT));
|
|
||||||
|
|
||||||
/* power on PLL1 and wait until stable */
|
/* power on PLL1 and wait until stable */
|
||||||
CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_PD;
|
CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_PD;
|
||||||
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK));
|
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK));
|
||||||
|
|
||||||
/* use PLL1 as clock source for BASE_M4_CLK (CPU) */
|
/* use PLL1 as clock source for BASE_M4_CLK (CPU) */
|
||||||
CGU_BASE_M4_CLK = ((CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT));
|
CGU_BASE_M4_CLK = CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||||
|
|
||||||
|
/* Move PLL1 up to 12MHz * 17 = 204MHz. */
|
||||||
|
CGU_PLL1_CTRL = CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL)
|
||||||
|
| CGU_PLL1_CTRL_PSEL(0)
|
||||||
|
| CGU_PLL1_CTRL_NSEL(0)
|
||||||
|
| CGU_PLL1_CTRL_MSEL(16);
|
||||||
|
|
||||||
|
/* wait until stable */
|
||||||
|
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK));
|
||||||
|
|
||||||
/* use XTAL_OSC as clock source for PLL0USB */
|
/* use XTAL_OSC as clock source for PLL0USB */
|
||||||
CGU_PLL0USB_CTRL = (CGU_PLL0USB_CTRL_PD
|
CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD
|
||||||
| CGU_PLL0USB_CTRL_AUTOBLOCK
|
| CGU_PLL0USB_CTRL_AUTOBLOCK
|
||||||
| (CGU_SRC_XTAL << CGU_PLL0USB_CTRL_CLK_SEL_SHIFT));
|
| CGU_PLL0USB_CTRL_CLK_SEL(CGU_SRC_XTAL);
|
||||||
while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK);
|
while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK);
|
||||||
|
|
||||||
/* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */
|
/* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */
|
||||||
CGU_PLL0USB_MDIV = ((0x07FFA << CGU_PLL0USB_MDIV_MDEC_SHIFT)
|
/* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */
|
||||||
| (0x0B << CGU_PLL0USB_SELP_MDEC_SHIFT)
|
CGU_PLL0USB_MDIV = 0x06167FFA;
|
||||||
| (0x10 << CGU_PLL0USB_SELI_MDEC_SHIFT)
|
CGU_PLL0USB_NP_DIV = 0x00302062;
|
||||||
| (0x0 << CGU_PLL0USB_SELR_MDEC_SHIFT));
|
|
||||||
CGU_PLL0USB_NP_DIV = (98 << CGU_PLL0USB_NP_DIV_PDEC_SHIFT)
|
|
||||||
| (514 << CGU_PLL0USB_NP_DIV_NDEC_SHIFT);
|
|
||||||
CGU_PLL0USB_CTRL |= (CGU_PLL0USB_CTRL_PD
|
CGU_PLL0USB_CTRL |= (CGU_PLL0USB_CTRL_PD
|
||||||
| CGU_PLL0USB_CTRL_DIRECTI
|
| CGU_PLL0USB_CTRL_DIRECTI
|
||||||
| CGU_PLL0USB_CTRL_DIRECTO
|
| CGU_PLL0USB_CTRL_DIRECTO
|
||||||
@ -197,8 +192,8 @@ void cpu_clock_init(void)
|
|||||||
while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK));
|
while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK));
|
||||||
|
|
||||||
/* use PLL0USB as clock source for USB0 */
|
/* use PLL0USB as clock source for USB0 */
|
||||||
CGU_BASE_USB0_CLK = (CGU_BASE_CLK_AUTOBLOCK
|
CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK
|
||||||
| (CGU_SRC_PLL0USB << CGU_BASE_CLK_SEL_SHIFT));
|
| CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssp1_init(void)
|
void ssp1_init(void)
|
||||||
@ -254,3 +249,54 @@ void ssp1_set_mode_max5864(void)
|
|||||||
SSP_MASTER,
|
SSP_MASTER,
|
||||||
SSP_SLAVE_OUT_ENABLE);
|
SSP_SLAVE_OUT_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pin_setup(void) {
|
||||||
|
/* Release CPLD JTAG pins */
|
||||||
|
scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4);
|
||||||
|
scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
||||||
|
scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
||||||
|
scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
||||||
|
|
||||||
|
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO;
|
||||||
|
GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK;
|
||||||
|
GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS;
|
||||||
|
GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI;
|
||||||
|
|
||||||
|
/* Configure SCU Pin Mux as GPIO */
|
||||||
|
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
||||||
|
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
||||||
|
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
||||||
|
|
||||||
|
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
||||||
|
|
||||||
|
scu_pinmux(SCU_PINMUX_BOOT0, SCU_GPIO_FAST);
|
||||||
|
scu_pinmux(SCU_PINMUX_BOOT1, SCU_GPIO_FAST);
|
||||||
|
scu_pinmux(SCU_PINMUX_BOOT2, SCU_GPIO_FAST);
|
||||||
|
scu_pinmux(SCU_PINMUX_BOOT3, SCU_GPIO_FAST);
|
||||||
|
|
||||||
|
/* Configure all GPIO as Input (safe state) */
|
||||||
|
GPIO0_DIR = 0;
|
||||||
|
GPIO1_DIR = 0;
|
||||||
|
GPIO2_DIR = 0;
|
||||||
|
GPIO3_DIR = 0;
|
||||||
|
GPIO4_DIR = 0;
|
||||||
|
GPIO5_DIR = 0;
|
||||||
|
GPIO6_DIR = 0;
|
||||||
|
GPIO7_DIR = 0;
|
||||||
|
|
||||||
|
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
||||||
|
GPIO2_DIR |= (PIN_LED1 | PIN_LED2 | PIN_LED3);
|
||||||
|
|
||||||
|
/* GPIO3[6] on P6_10 as output. */
|
||||||
|
GPIO3_DIR |= PIN_EN1V8;
|
||||||
|
|
||||||
|
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */
|
||||||
|
scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
||||||
|
scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
||||||
|
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
|
||||||
|
scu_pinmux(SCU_SSP1_SSEL, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_1v8_power(void) {
|
||||||
|
gpio_set(PORT_EN1V8, PIN_EN1V8);
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
* Copyright 2012 Benjamin Vernoux <titanmkd@gmail.com>
|
* Copyright 2012 Benjamin Vernoux <titanmkd@gmail.com>
|
||||||
* Copyright (C) 2012 Jared Boone <jared@sharebrained.com>
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
*
|
*
|
||||||
* This file is part of HackRF.
|
* This file is part of HackRF.
|
||||||
*
|
*
|
||||||
@ -29,6 +29,8 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/* hardware identification number */
|
/* hardware identification number */
|
||||||
#define BOARD_ID_JELLYBEAN 0
|
#define BOARD_ID_JELLYBEAN 0
|
||||||
#define BOARD_ID_JAWBREAKER 1
|
#define BOARD_ID_JAWBREAKER 1
|
||||||
@ -198,11 +200,17 @@ extern "C"
|
|||||||
|
|
||||||
/* TODO add other Pins */
|
/* TODO add other Pins */
|
||||||
|
|
||||||
|
void delay(uint32_t duration);
|
||||||
|
|
||||||
void cpu_clock_init(void);
|
void cpu_clock_init(void);
|
||||||
void ssp1_init(void);
|
void ssp1_init(void);
|
||||||
void ssp1_set_mode_max2837(void);
|
void ssp1_set_mode_max2837(void);
|
||||||
void ssp1_set_mode_max5864(void);
|
void ssp1_set_mode_max5864(void);
|
||||||
|
|
||||||
|
void pin_setup(void);
|
||||||
|
|
||||||
|
void enable_1v8_power(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Jared Boone <jared@sharebrained.com>
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
*
|
*
|
||||||
* This file is part of HackRF.
|
* This file is part of HackRF.
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Jared Boone <jared@sharebrained.com>
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
*
|
*
|
||||||
* This file is part of HackRF.
|
* This file is part of HackRF.
|
||||||
*
|
*
|
||||||
|
@ -379,6 +379,8 @@ void rffc5071_tx(uint8_t gpo) {
|
|||||||
gpo |= SWITCHCTRL_NO_TX_AMP_PWR;
|
gpo |= SWITCHCTRL_NO_TX_AMP_PWR;
|
||||||
gpo |= (SWITCHCTRL_TX | SWITCHCTRL_NO_RX_AMP_PWR);
|
gpo |= (SWITCHCTRL_TX | SWITCHCTRL_NO_RX_AMP_PWR);
|
||||||
rffc5071_set_gpo(gpo);
|
rffc5071_set_gpo(gpo);
|
||||||
|
#else
|
||||||
|
(void)gpo;
|
||||||
#endif
|
#endif
|
||||||
rffc5071_regs_commit();
|
rffc5071_regs_commit();
|
||||||
|
|
||||||
@ -403,6 +405,8 @@ void rffc5071_rx(uint8_t gpo) {
|
|||||||
gpo |= SWITCHCTRL_NO_RX_AMP_PWR;
|
gpo |= SWITCHCTRL_NO_RX_AMP_PWR;
|
||||||
gpo |= SWITCHCTRL_NO_TX_AMP_PWR;
|
gpo |= SWITCHCTRL_NO_TX_AMP_PWR;
|
||||||
rffc5071_set_gpo(gpo);
|
rffc5071_set_gpo(gpo);
|
||||||
|
#else
|
||||||
|
(void)gpo;
|
||||||
#endif
|
#endif
|
||||||
rffc5071_regs_commit();
|
rffc5071_regs_commit();
|
||||||
|
|
||||||
|
301
firmware/common/sgpio.c
Normal file
301
firmware/common/sgpio.c
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libopencm3/lpc43xx/scu.h>
|
||||||
|
#include <libopencm3/lpc43xx/sgpio.h>
|
||||||
|
|
||||||
|
#include <hackrf_core.h>
|
||||||
|
|
||||||
|
void sgpio_configure_pin_functions() {
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO2, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO3, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO4, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO5, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO6, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO7, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO8, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO9, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO10, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO11, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO12, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO13, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO14, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
||||||
|
scu_pinmux(SCU_PINMUX_SGPIO15, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sgpio_test_interface() {
|
||||||
|
const uint_fast8_t host_clock_sgpio_pin = 8; // Input
|
||||||
|
const uint_fast8_t host_capture_sgpio_pin = 9; // Input
|
||||||
|
const uint_fast8_t host_disable_sgpio_pin = 10; // Output
|
||||||
|
const uint_fast8_t host_direction_sgpio_pin = 11; // Output
|
||||||
|
|
||||||
|
SGPIO_GPIO_OENREG = 0; // All inputs for the moment.
|
||||||
|
|
||||||
|
// Disable all counters during configuration
|
||||||
|
SGPIO_CTRL_ENABLE = 0;
|
||||||
|
|
||||||
|
sgpio_configure_pin_functions();
|
||||||
|
|
||||||
|
// Make all SGPIO controlled by SGPIO's "GPIO" registers
|
||||||
|
for (uint_fast8_t i = 0; i < 16; i++) {
|
||||||
|
SGPIO_OUT_MUX_CFG(i) = (0L << 4) | (4L << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set SGPIO output values.
|
||||||
|
SGPIO_GPIO_OUTREG = (1L << host_direction_sgpio_pin)
|
||||||
|
| (1L << host_disable_sgpio_pin);
|
||||||
|
|
||||||
|
// Enable SGPIO pin outputs.
|
||||||
|
SGPIO_GPIO_OENREG = (1L << host_direction_sgpio_pin)
|
||||||
|
| (1L << host_disable_sgpio_pin) | (0L << host_capture_sgpio_pin)
|
||||||
|
| (0L << host_clock_sgpio_pin) | (0xFF << 0);
|
||||||
|
|
||||||
|
// Configure SGPIO slices.
|
||||||
|
|
||||||
|
// Enable codec data stream.
|
||||||
|
SGPIO_GPIO_OUTREG &= ~(1L << host_disable_sgpio_pin);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
for (uint_fast8_t i = 0; i < 8; i++) {
|
||||||
|
SGPIO_GPIO_OUTREG ^= (1L << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgpio_configure_for_tx() {
|
||||||
|
// Disable all counters during configuration
|
||||||
|
SGPIO_CTRL_ENABLE = 0;
|
||||||
|
|
||||||
|
sgpio_configure_pin_functions();
|
||||||
|
|
||||||
|
// Set SGPIO output values.
|
||||||
|
SGPIO_GPIO_OUTREG =
|
||||||
|
(1L << 11) | // direction
|
||||||
|
(1L << 10); // disable
|
||||||
|
|
||||||
|
// Enable SGPIO pin outputs.
|
||||||
|
SGPIO_GPIO_OENREG =
|
||||||
|
(1L << 11) | // direction: TX: data to CPLD
|
||||||
|
(1L << 10) | // disable
|
||||||
|
(0L << 9) | // capture
|
||||||
|
(0L << 8) | // clock
|
||||||
|
0xFF; // data: output
|
||||||
|
|
||||||
|
SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock
|
||||||
|
SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier
|
||||||
|
SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable
|
||||||
|
SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction
|
||||||
|
|
||||||
|
for(uint_fast8_t i=0; i<8; i++) {
|
||||||
|
// SGPIO pin 0 outputs slice A bit "i".
|
||||||
|
SGPIO_OUT_MUX_CFG(i) =
|
||||||
|
(0L << 4) | // P_OE_CFG = 0
|
||||||
|
(9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice A
|
||||||
|
SGPIO_MUX_CFG(SGPIO_SLICE_A) =
|
||||||
|
(0L << 12) | // CONCAT_ORDER = 0 (self-loop)
|
||||||
|
(1L << 11) | // CONCAT_ENABLE = 1 (concatenate data)
|
||||||
|
(0L << 9) | // QUALIFIER_SLICE_MODE = X
|
||||||
|
(1L << 7) | // QUALIFIER_PIN_MODE = 1 (SGPIO9)
|
||||||
|
(3L << 5) | // QUALIFIER_MODE = 3 (external SGPIO pin)
|
||||||
|
(0L << 3) | // CLK_SOURCE_SLICE_MODE = X
|
||||||
|
(0L << 1) | // CLK_SOURCE_PIN_MODE = 0 (SGPIO8)
|
||||||
|
(1L << 0); // EXT_CLK_ENABLE = 1, external clock signal (slice)
|
||||||
|
|
||||||
|
SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_A) =
|
||||||
|
(0L << 8) | // INV_QUALIFIER = 0 (use normal qualifier)
|
||||||
|
(3L << 6) | // PARALLEL_MODE = 3 (shift 8 bits per clock)
|
||||||
|
(0L << 4) | // DATA_CAPTURE_MODE = 0 (detect rising edge)
|
||||||
|
(0L << 3) | // INV_OUT_CLK = 0 (normal clock)
|
||||||
|
(1L << 2) | // CLKGEN_MODE = 1 (use external pin clock)
|
||||||
|
(0L << 1) | // CLK_CAPTURE_MODE = 0 (use rising clock edge)
|
||||||
|
(0L << 0); // MATCH_MODE = 0 (do not match data)
|
||||||
|
|
||||||
|
SGPIO_PRESET(SGPIO_SLICE_A) = 0;
|
||||||
|
SGPIO_COUNT(SGPIO_SLICE_A) = 0;
|
||||||
|
SGPIO_POS(SGPIO_SLICE_A) = (0x3L << 8) | (0x3L << 0);
|
||||||
|
SGPIO_REG(SGPIO_SLICE_A) = 0x80808080; // Primary output data register
|
||||||
|
SGPIO_REG_SS(SGPIO_SLICE_A) = 0x80808080; // Shadow output data register
|
||||||
|
|
||||||
|
// Start SGPIO operation by enabling slice clocks.
|
||||||
|
SGPIO_CTRL_ENABLE =
|
||||||
|
(1L << SGPIO_SLICE_A)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgpio_configure_for_rx() {
|
||||||
|
// Disable all counters during configuration
|
||||||
|
SGPIO_CTRL_ENABLE = 0;
|
||||||
|
|
||||||
|
sgpio_configure_pin_functions();
|
||||||
|
|
||||||
|
// Set SGPIO output values.
|
||||||
|
SGPIO_GPIO_OUTREG =
|
||||||
|
(0L << 11) | // direction
|
||||||
|
(1L << 10); // disable
|
||||||
|
|
||||||
|
// Enable SGPIO pin outputs.
|
||||||
|
SGPIO_GPIO_OENREG =
|
||||||
|
(1L << 11) | // direction: RX: data from CPLD
|
||||||
|
(1L << 10) | // disable
|
||||||
|
(0L << 9) | // capture
|
||||||
|
(0L << 8) | // clock
|
||||||
|
0x00; // data: input
|
||||||
|
|
||||||
|
SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock
|
||||||
|
SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier
|
||||||
|
SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable
|
||||||
|
SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction
|
||||||
|
|
||||||
|
for(uint_fast8_t i=0; i<8; i++) {
|
||||||
|
SGPIO_OUT_MUX_CFG(i) =
|
||||||
|
(0L << 4) | // P_OE_CFG = 0
|
||||||
|
(9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice A
|
||||||
|
SGPIO_MUX_CFG(SGPIO_SLICE_A) =
|
||||||
|
(0L << 12) | // CONCAT_ORDER = X
|
||||||
|
(0L << 11) | // CONCAT_ENABLE = 0 (concatenate data)
|
||||||
|
(0L << 9) | // QUALIFIER_SLICE_MODE = X
|
||||||
|
(1L << 7) | // QUALIFIER_PIN_MODE = 1 (SGPIO9)
|
||||||
|
(3L << 5) | // QUALIFIER_MODE = 3 (external SGPIO pin)
|
||||||
|
(0L << 3) | // CLK_SOURCE_SLICE_MODE = X
|
||||||
|
(0L << 1) | // CLK_SOURCE_PIN_MODE = 0 (SGPIO8)
|
||||||
|
(1L << 0); // EXT_CLK_ENABLE = 1, external clock signal (slice)
|
||||||
|
|
||||||
|
SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_A) =
|
||||||
|
(0L << 8) | // INV_QUALIFIER = 0 (use normal qualifier)
|
||||||
|
(3L << 6) | // PARALLEL_MODE = 3 (shift 8 bits per clock)
|
||||||
|
(0L << 4) | // DATA_CAPTURE_MODE = 0 (detect rising edge)
|
||||||
|
(0L << 3) | // INV_OUT_CLK = X
|
||||||
|
(1L << 2) | // CLKGEN_MODE = 1 (use external pin clock)
|
||||||
|
(1L << 1) | // CLK_CAPTURE_MODE = 1 (use falling clock edge)
|
||||||
|
(0L << 0); // MATCH_MODE = 0 (do not match data)
|
||||||
|
|
||||||
|
SGPIO_PRESET(SGPIO_SLICE_A) = 0;
|
||||||
|
SGPIO_COUNT(SGPIO_SLICE_A) = 0;
|
||||||
|
SGPIO_POS(SGPIO_SLICE_A) = (0 << 8) | (0 << 0);
|
||||||
|
SGPIO_REG(SGPIO_SLICE_A) = 0xCAFEBABE; // Primary output data register
|
||||||
|
SGPIO_REG_SS(SGPIO_SLICE_A) = 0xDEADBEEF; // Shadow output data register
|
||||||
|
|
||||||
|
// Start SGPIO operation by enabling slice clocks.
|
||||||
|
SGPIO_CTRL_ENABLE =
|
||||||
|
(1L << SGPIO_SLICE_A)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgpio_configure_for_rx_deep() {
|
||||||
|
// Disable all counters during configuration
|
||||||
|
SGPIO_CTRL_ENABLE = 0;
|
||||||
|
|
||||||
|
sgpio_configure_pin_functions();
|
||||||
|
|
||||||
|
// Set SGPIO output values.
|
||||||
|
SGPIO_GPIO_OUTREG =
|
||||||
|
(0L << 11) | // direction
|
||||||
|
(1L << 10); // disable
|
||||||
|
|
||||||
|
// Enable SGPIO pin outputs.
|
||||||
|
SGPIO_GPIO_OENREG =
|
||||||
|
(1L << 11) | // direction: RX: data from CPLD
|
||||||
|
(1L << 10) | // disable
|
||||||
|
(0L << 9) | // capture
|
||||||
|
(0L << 8) | // clock
|
||||||
|
0x00; // data: input
|
||||||
|
|
||||||
|
SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock
|
||||||
|
SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier
|
||||||
|
SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable
|
||||||
|
SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction
|
||||||
|
|
||||||
|
for(uint_fast8_t i=0; i<8; i++) {
|
||||||
|
SGPIO_OUT_MUX_CFG(i) =
|
||||||
|
(0L << 4) | // P_OE_CFG = 0
|
||||||
|
(9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a)
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint_fast8_t slice_indices[] = {
|
||||||
|
SGPIO_SLICE_A,
|
||||||
|
SGPIO_SLICE_I,
|
||||||
|
SGPIO_SLICE_E,
|
||||||
|
SGPIO_SLICE_J,
|
||||||
|
SGPIO_SLICE_C,
|
||||||
|
SGPIO_SLICE_K,
|
||||||
|
SGPIO_SLICE_F,
|
||||||
|
SGPIO_SLICE_L,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t slice_enable_mask = 0;
|
||||||
|
for(uint_fast8_t i=0; i<8; i++) {
|
||||||
|
uint_fast8_t slice_index = slice_indices[i];
|
||||||
|
const uint_fast8_t concat_order = (slice_index == SGPIO_SLICE_A) ? 0 : 3;
|
||||||
|
const uint_fast8_t concat_enable = (slice_index == SGPIO_SLICE_A) ? 0 : 1;
|
||||||
|
SGPIO_MUX_CFG(slice_index) =
|
||||||
|
(concat_order << 12) | // CONCAT_ORDER = 3 (eight slices)
|
||||||
|
(concat_enable << 11) | // CONCAT_ENABLE = 1 (concatenate data)
|
||||||
|
(0L << 9) | // QUALIFIER_SLICE_MODE = X
|
||||||
|
(1L << 7) | // QUALIFIER_PIN_MODE = 1 (SGPIO9)
|
||||||
|
(3L << 5) | // QUALIFIER_MODE = 3 (external SGPIO pin)
|
||||||
|
(0L << 3) | // CLK_SOURCE_SLICE_MODE = X
|
||||||
|
(0L << 1) | // CLK_SOURCE_PIN_MODE = 0 (SGPIO8)
|
||||||
|
(1L << 0); // EXT_CLK_ENABLE = 1, external clock signal (slice)
|
||||||
|
|
||||||
|
SGPIO_SLICE_MUX_CFG(slice_index) =
|
||||||
|
(0L << 8) | // INV_QUALIFIER = 0 (use normal qualifier)
|
||||||
|
(3L << 6) | // PARALLEL_MODE = 3 (shift 8 bits per clock)
|
||||||
|
(0L << 4) | // DATA_CAPTURE_MODE = 0 (detect rising edge)
|
||||||
|
(0L << 3) | // INV_OUT_CLK = X
|
||||||
|
(1L << 2) | // CLKGEN_MODE = 1 (use external pin clock)
|
||||||
|
(1L << 1) | // CLK_CAPTURE_MODE = 1 (use falling clock edge)
|
||||||
|
(0L << 0); // MATCH_MODE = 0 (do not match data)
|
||||||
|
|
||||||
|
SGPIO_PRESET(slice_index) = 0; // External clock, don't care
|
||||||
|
SGPIO_COUNT(slice_index) = 0; // External clock, don't care
|
||||||
|
SGPIO_POS(slice_index) = (0x1f << 8) | (0x1f << 0);
|
||||||
|
SGPIO_REG(slice_index) = 0xFFFFFFFF; // Primary output data register
|
||||||
|
SGPIO_REG_SS(slice_index) = 0xFFFFFFFF; // Shadow output data register
|
||||||
|
|
||||||
|
slice_enable_mask |= (1 << slice_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start SGPIO operation by enabling slice clocks.
|
||||||
|
SGPIO_CTRL_ENABLE = slice_enable_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgpio_cpld_stream_enable() {
|
||||||
|
// Enable codec data stream.
|
||||||
|
SGPIO_GPIO_OUTREG &= ~(1L << 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgpio_cpld_stream_disable() {
|
||||||
|
// Disable codec data stream.
|
||||||
|
SGPIO_GPIO_OUTREG |= (1L << 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sgpio_cpld_stream_is_enabled() {
|
||||||
|
return (SGPIO_GPIO_OUTREG & (1L << 10)) == 0;
|
||||||
|
}
|
34
firmware/common/sgpio.h
Normal file
34
firmware/common/sgpio.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SGPIO_H__
|
||||||
|
#define __SGPIO_H__
|
||||||
|
|
||||||
|
void sgpio_configure_pin_functions();
|
||||||
|
void sgpio_test_interface();
|
||||||
|
void sgpio_configure_for_tx();
|
||||||
|
void sgpio_configure_for_rx();
|
||||||
|
void sgpio_configure_for_rx_deep();
|
||||||
|
void sgpio_cpld_stream_enable();
|
||||||
|
void sgpio_cpld_stream_disable();
|
||||||
|
bool sgpio_cpld_stream_is_enabled();
|
||||||
|
|
||||||
|
#endif//__SGPIO_H__
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Michael Ossmann
|
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
* Copyright 2012 Jared Boone
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
*
|
*
|
||||||
* This file is part of HackRF.
|
* This file is part of HackRF.
|
||||||
*
|
*
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 Michael Ossmann
|
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
|
||||||
* Copyright 2012 Jared Boone
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
*
|
*
|
||||||
* This file is part of HackRF.
|
* This file is part of HackRF.
|
||||||
*
|
*
|
||||||
|
@ -28,32 +28,6 @@
|
|||||||
#include "max2837.h"
|
#include "max2837.h"
|
||||||
#include "rffc5071.h"
|
#include "rffc5071.h"
|
||||||
|
|
||||||
void pin_setup(void)
|
|
||||||
{
|
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */
|
|
||||||
GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1|PIN_LED2|PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
const uint32_t freq = 2441000000U;
|
const uint32_t freq = 2441000000U;
|
||||||
|
@ -1,9 +1,30 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#
|
||||||
|
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
#
|
||||||
|
# This file is part of HackRF.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
BINARY = sgpio-rx
|
BINARY = sgpio-rx
|
||||||
|
|
||||||
SRC = $(BINARY).c \
|
SRC = $(BINARY).c \
|
||||||
../common/hackrf_core.c \
|
../common/hackrf_core.c \
|
||||||
|
../common/sgpio.c \
|
||||||
../common/si5351c.c \
|
../common/si5351c.c \
|
||||||
../common/max2837.c \
|
../common/max2837.c \
|
||||||
../common/max5864.c \
|
../common/max5864.c \
|
||||||
|
@ -30,172 +30,10 @@
|
|||||||
#include <max5864.h>
|
#include <max5864.h>
|
||||||
#include <max2837.h>
|
#include <max2837.h>
|
||||||
#include <rffc5071.h>
|
#include <rffc5071.h>
|
||||||
|
#include <sgpio.h>
|
||||||
|
|
||||||
void pin_setup(void) {
|
void tx_test() {
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
sgpio_configure_for_tx();
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1 | PIN_LED2 | PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
|
|
||||||
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */
|
|
||||||
scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
|
||||||
scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
|
||||||
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
|
|
||||||
scu_pinmux(SCU_SSP1_SSEL, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable_1v8_power() {
|
|
||||||
gpio_set(PORT_EN1V8, PIN_EN1V8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void release_cpld_jtag_pins() {
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4);
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
|
||||||
|
|
||||||
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO;
|
|
||||||
GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK;
|
|
||||||
GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS;
|
|
||||||
GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure_sgpio_pin_functions() {
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO2, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO3, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO4, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO5, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO6, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO7, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO8, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO9, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO10, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO11, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO12, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO13, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO14, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO15, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_sgpio_interface() {
|
|
||||||
const uint_fast8_t host_clock_sgpio_pin = 8; // Input
|
|
||||||
const uint_fast8_t host_capture_sgpio_pin = 9; // Input
|
|
||||||
const uint_fast8_t host_disable_sgpio_pin = 10; // Output
|
|
||||||
const uint_fast8_t host_direction_sgpio_pin = 11; // Output
|
|
||||||
|
|
||||||
SGPIO_GPIO_OENREG = 0; // All inputs for the moment.
|
|
||||||
|
|
||||||
// Disable all counters during configuration
|
|
||||||
SGPIO_CTRL_ENABLE = 0;
|
|
||||||
|
|
||||||
configure_sgpio_pin_functions();
|
|
||||||
|
|
||||||
// Make all SGPIO controlled by SGPIO's "GPIO" registers
|
|
||||||
for (uint_fast8_t i = 0; i < 16; i++) {
|
|
||||||
SGPIO_OUT_MUX_CFG(i) = (0L << 4) | (4L << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set SGPIO output values.
|
|
||||||
SGPIO_GPIO_OUTREG = (1L << host_direction_sgpio_pin)
|
|
||||||
| (1L << host_disable_sgpio_pin);
|
|
||||||
|
|
||||||
// Enable SGPIO pin outputs.
|
|
||||||
SGPIO_GPIO_OENREG = (1L << host_direction_sgpio_pin)
|
|
||||||
| (1L << host_disable_sgpio_pin) | (0L << host_capture_sgpio_pin)
|
|
||||||
| (0L << host_clock_sgpio_pin) | (0xFF << 0);
|
|
||||||
|
|
||||||
// Configure SGPIO slices.
|
|
||||||
|
|
||||||
// Enable codec data stream.
|
|
||||||
SGPIO_GPIO_OUTREG &= ~(1L << host_disable_sgpio_pin);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
for (uint_fast8_t i = 0; i < 8; i++) {
|
|
||||||
SGPIO_GPIO_OUTREG ^= (1L << i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure_sgpio_test_tx() {
|
|
||||||
// Disable all counters during configuration
|
|
||||||
SGPIO_CTRL_ENABLE = 0;
|
|
||||||
|
|
||||||
configure_sgpio_pin_functions();
|
|
||||||
|
|
||||||
// Set SGPIO output values.
|
|
||||||
SGPIO_GPIO_OUTREG =
|
|
||||||
(1L << 11) | // direction
|
|
||||||
(1L << 10); // disable
|
|
||||||
|
|
||||||
// Enable SGPIO pin outputs.
|
|
||||||
SGPIO_GPIO_OENREG =
|
|
||||||
(1L << 11) | // direction: TX: data to CPLD
|
|
||||||
(1L << 10) | // disable
|
|
||||||
(0L << 9) | // capture
|
|
||||||
(0L << 8) | // clock
|
|
||||||
0xFF; // data: output
|
|
||||||
|
|
||||||
SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock
|
|
||||||
SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier
|
|
||||||
SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable
|
|
||||||
SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction
|
|
||||||
|
|
||||||
for(uint_fast8_t i=0; i<8; i++) {
|
|
||||||
// SGPIO pin 0 outputs slice A bit "i".
|
|
||||||
SGPIO_OUT_MUX_CFG(i) =
|
|
||||||
(0L << 4) | // P_OE_CFG = 0
|
|
||||||
(9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice A
|
|
||||||
SGPIO_MUX_CFG(SGPIO_SLICE_A) =
|
|
||||||
(0L << 12) | // CONCAT_ORDER = 0 (self-loop)
|
|
||||||
(1L << 11) | // CONCAT_ENABLE = 1 (concatenate data)
|
|
||||||
(0L << 9) | // QUALIFIER_SLICE_MODE = X
|
|
||||||
(1L << 7) | // QUALIFIER_PIN_MODE = 1 (SGPIO9)
|
|
||||||
(3L << 5) | // QUALIFIER_MODE = 3 (external SGPIO pin)
|
|
||||||
(0L << 3) | // CLK_SOURCE_SLICE_MODE = X
|
|
||||||
(0L << 1) | // CLK_SOURCE_PIN_MODE = 0 (SGPIO8)
|
|
||||||
(1L << 0); // EXT_CLK_ENABLE = 1, external clock signal
|
|
||||||
|
|
||||||
SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_A) =
|
|
||||||
(0L << 8) | // INV_QUALIFIER = 0 (use normal qualifier)
|
|
||||||
(3L << 6) | // PARALLEL_MODE = 3 (shift 8 bits per clock)
|
|
||||||
(0L << 4) | // DATA_CAPTURE_MODE = 0 (detect rising edge)
|
|
||||||
(0L << 3) | // INV_OUT_CLK = 0 (normal clock)
|
|
||||||
(1L << 2) | // CLKGEN_MODE = 1 (use external pin clock)
|
|
||||||
(0L << 1) | // CLK_CAPTURE_MODE = 0 (use rising clock edge)
|
|
||||||
(0L << 0); // MATCH_MODE = 0 (do not match data)
|
|
||||||
|
|
||||||
SGPIO_PRESET(SGPIO_SLICE_A) = 0;
|
|
||||||
SGPIO_COUNT(SGPIO_SLICE_A) = 0;
|
|
||||||
SGPIO_POS(SGPIO_SLICE_A) = (0x3L << 8) | (0x3L << 0);
|
|
||||||
SGPIO_REG(SGPIO_SLICE_A) = 0x80808080; // Primary output data register
|
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_A) = 0x80808080; // Shadow output data register
|
|
||||||
|
|
||||||
// Start SGPIO operation by enabling slice clocks.
|
|
||||||
SGPIO_CTRL_ENABLE =
|
|
||||||
(1L << SGPIO_SLICE_A)
|
|
||||||
;
|
|
||||||
|
|
||||||
// LSB goes out first, samples are 0x<Q1><I1><Q0><I0>
|
// LSB goes out first, samples are 0x<Q1><I1><Q0><I0>
|
||||||
volatile uint32_t buffer[] = {
|
volatile uint32_t buffer[] = {
|
||||||
@ -206,8 +44,7 @@ void configure_sgpio_test_tx() {
|
|||||||
};
|
};
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
// Enable codec data stream.
|
sgpio_cpld_stream_enable();
|
||||||
SGPIO_GPIO_OUTREG &= ~(1L << 10);
|
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
while(SGPIO_STATUS_1 == 0);
|
while(SGPIO_STATUS_1 == 0);
|
||||||
@ -216,72 +53,15 @@ void configure_sgpio_test_tx() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void configure_sgpio_test_rx() {
|
void rx_test() {
|
||||||
// Disable all counters during configuration
|
sgpio_configure_for_rx();
|
||||||
SGPIO_CTRL_ENABLE = 0;
|
|
||||||
|
|
||||||
configure_sgpio_pin_functions();
|
|
||||||
|
|
||||||
// Set SGPIO output values.
|
|
||||||
SGPIO_GPIO_OUTREG =
|
|
||||||
(0L << 11) | // direction
|
|
||||||
(1L << 10); // disable
|
|
||||||
|
|
||||||
// Enable SGPIO pin outputs.
|
|
||||||
SGPIO_GPIO_OENREG =
|
|
||||||
(1L << 11) | // direction: RX: data from CPLD
|
|
||||||
(1L << 10) | // disable
|
|
||||||
(0L << 9) | // capture
|
|
||||||
(0L << 8) | // clock
|
|
||||||
0x00; // data: input
|
|
||||||
|
|
||||||
SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock
|
|
||||||
SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier
|
|
||||||
SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable
|
|
||||||
SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction
|
|
||||||
|
|
||||||
for(uint_fast8_t i=0; i<8; i++) {
|
|
||||||
SGPIO_OUT_MUX_CFG(i) =
|
|
||||||
(0L << 4) | // P_OE_CFG = 0
|
|
||||||
(9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice A
|
|
||||||
SGPIO_MUX_CFG(SGPIO_SLICE_A) =
|
|
||||||
(0L << 12) | // CONCAT_ORDER = X
|
|
||||||
(0L << 11) | // CONCAT_ENABLE = 0 (concatenate data)
|
|
||||||
(0L << 9) | // QUALIFIER_SLICE_MODE = X
|
|
||||||
(1L << 7) | // QUALIFIER_PIN_MODE = 1 (SGPIO9)
|
|
||||||
(3L << 5) | // QUALIFIER_MODE = 3 (external SGPIO pin)
|
|
||||||
(0L << 3) | // CLK_SOURCE_SLICE_MODE = X
|
|
||||||
(0L << 1) | // CLK_SOURCE_PIN_MODE = 0 (SGPIO8)
|
|
||||||
(1L << 0); // EXT_CLK_ENABLE = 1, external clock signal
|
|
||||||
|
|
||||||
SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_A) =
|
|
||||||
(0L << 8) | // INV_QUALIFIER = 0 (use normal qualifier)
|
|
||||||
(3L << 6) | // PARALLEL_MODE = 3 (shift 8 bits per clock)
|
|
||||||
(0L << 4) | // DATA_CAPTURE_MODE = 0 (detect rising edge)
|
|
||||||
(0L << 3) | // INV_OUT_CLK = X
|
|
||||||
(1L << 2) | // CLKGEN_MODE = 1 (use external pin clock)
|
|
||||||
(1L << 1) | // CLK_CAPTURE_MODE = 1 (use falling clock edge)
|
|
||||||
(0L << 0); // MATCH_MODE = 0 (do not match data)
|
|
||||||
|
|
||||||
SGPIO_PRESET(SGPIO_SLICE_A) = 0;
|
|
||||||
SGPIO_COUNT(SGPIO_SLICE_A) = 0;
|
|
||||||
SGPIO_POS(SGPIO_SLICE_A) = (0x3L << 8) | (0x3L << 0);
|
|
||||||
SGPIO_REG(SGPIO_SLICE_A) = 0xCAFEBABE; // Primary output data register
|
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_A) = 0xDEADBEEF; // Shadow output data register
|
|
||||||
|
|
||||||
// Start SGPIO operation by enabling slice clocks.
|
|
||||||
SGPIO_CTRL_ENABLE = (1L << SGPIO_SLICE_A);
|
|
||||||
|
|
||||||
volatile uint32_t buffer[4096];
|
volatile uint32_t buffer[4096];
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
int16_t magsq;
|
int16_t magsq;
|
||||||
int8_t sigi, sigq;
|
int8_t sigi, sigq;
|
||||||
|
|
||||||
// Enable codec data stream.
|
sgpio_cpld_stream_enable();
|
||||||
SGPIO_GPIO_OUTREG &= ~(1L << 10);
|
|
||||||
|
|
||||||
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */
|
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */
|
||||||
while(true) {
|
while(true) {
|
||||||
@ -317,11 +97,11 @@ int main(void) {
|
|||||||
enable_1v8_power();
|
enable_1v8_power();
|
||||||
cpu_clock_init();
|
cpu_clock_init();
|
||||||
|
|
||||||
CGU_BASE_PERIPH_CLK = (CGU_BASE_CLK_AUTOBLOCK
|
CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK
|
||||||
| (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT));
|
| CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||||
|
|
||||||
CGU_BASE_APB1_CLK = (CGU_BASE_CLK_AUTOBLOCK
|
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK
|
||||||
| (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT));
|
| CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||||
|
|
||||||
ssp1_init();
|
ssp1_init();
|
||||||
ssp1_set_mode_max2837();
|
ssp1_set_mode_max2837();
|
||||||
@ -339,7 +119,7 @@ int main(void) {
|
|||||||
|
|
||||||
ssp1_set_mode_max5864();
|
ssp1_set_mode_max5864();
|
||||||
max5864_xcvr();
|
max5864_xcvr();
|
||||||
configure_sgpio_test_rx();
|
rx_test();
|
||||||
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */
|
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -1,9 +1,30 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#
|
||||||
|
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
#
|
||||||
|
# This file is part of HackRF.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
BINARY = sgpio
|
BINARY = sgpio
|
||||||
|
|
||||||
SRC = $(BINARY).c \
|
SRC = $(BINARY).c \
|
||||||
../common/hackrf_core.c \
|
../common/hackrf_core.c \
|
||||||
|
../common/sgpio.c \
|
||||||
../common/si5351c.c \
|
../common/si5351c.c \
|
||||||
../common/max2837.c \
|
../common/max2837.c \
|
||||||
../common/max5864.c
|
../common/max5864.c
|
||||||
|
@ -28,172 +28,10 @@
|
|||||||
|
|
||||||
#include <hackrf_core.h>
|
#include <hackrf_core.h>
|
||||||
#include <max5864.h>
|
#include <max5864.h>
|
||||||
|
#include <sgpio.h>
|
||||||
|
|
||||||
void pin_setup(void) {
|
void tx_test() {
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
sgpio_configure_for_tx();
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1 | PIN_LED2 | PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
|
|
||||||
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */
|
|
||||||
scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
|
||||||
scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
|
||||||
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
|
|
||||||
scu_pinmux(SCU_SSP1_SSEL, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable_1v8_power() {
|
|
||||||
gpio_set(PORT_EN1V8, PIN_EN1V8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void release_cpld_jtag_pins() {
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4);
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
|
||||||
|
|
||||||
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO;
|
|
||||||
GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK;
|
|
||||||
GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS;
|
|
||||||
GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure_sgpio_pin_functions() {
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO2, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO3, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO4, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO5, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO6, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO7, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO8, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO9, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO10, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO11, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO12, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO13, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO14, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO15, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_sgpio_interface() {
|
|
||||||
const uint_fast8_t host_clock_sgpio_pin = 8; // Input
|
|
||||||
const uint_fast8_t host_capture_sgpio_pin = 9; // Input
|
|
||||||
const uint_fast8_t host_disable_sgpio_pin = 10; // Output
|
|
||||||
const uint_fast8_t host_direction_sgpio_pin = 11; // Output
|
|
||||||
|
|
||||||
SGPIO_GPIO_OENREG = 0; // All inputs for the moment.
|
|
||||||
|
|
||||||
// Disable all counters during configuration
|
|
||||||
SGPIO_CTRL_ENABLE = 0;
|
|
||||||
|
|
||||||
configure_sgpio_pin_functions();
|
|
||||||
|
|
||||||
// Make all SGPIO controlled by SGPIO's "GPIO" registers
|
|
||||||
for (uint_fast8_t i = 0; i < 16; i++) {
|
|
||||||
SGPIO_OUT_MUX_CFG(i) = (0L << 4) | (4L << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set SGPIO output values.
|
|
||||||
SGPIO_GPIO_OUTREG = (1L << host_direction_sgpio_pin)
|
|
||||||
| (1L << host_disable_sgpio_pin);
|
|
||||||
|
|
||||||
// Enable SGPIO pin outputs.
|
|
||||||
SGPIO_GPIO_OENREG = (1L << host_direction_sgpio_pin)
|
|
||||||
| (1L << host_disable_sgpio_pin) | (0L << host_capture_sgpio_pin)
|
|
||||||
| (0L << host_clock_sgpio_pin) | (0xFF << 0);
|
|
||||||
|
|
||||||
// Configure SGPIO slices.
|
|
||||||
|
|
||||||
// Enable codec data stream.
|
|
||||||
SGPIO_GPIO_OUTREG &= ~(1L << host_disable_sgpio_pin);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
for (uint_fast8_t i = 0; i < 8; i++) {
|
|
||||||
SGPIO_GPIO_OUTREG ^= (1L << i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure_sgpio_test_tx() {
|
|
||||||
// Disable all counters during configuration
|
|
||||||
SGPIO_CTRL_ENABLE = 0;
|
|
||||||
|
|
||||||
configure_sgpio_pin_functions();
|
|
||||||
|
|
||||||
// Set SGPIO output values.
|
|
||||||
SGPIO_GPIO_OUTREG =
|
|
||||||
(1L << 11) | // direction
|
|
||||||
(1L << 10); // disable
|
|
||||||
|
|
||||||
// Enable SGPIO pin outputs.
|
|
||||||
SGPIO_GPIO_OENREG =
|
|
||||||
(1L << 11) | // direction: TX: data to CPLD
|
|
||||||
(1L << 10) | // disable
|
|
||||||
(0L << 9) | // capture
|
|
||||||
(0L << 8) | // clock
|
|
||||||
0xFF; // data: output
|
|
||||||
|
|
||||||
SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock
|
|
||||||
SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier
|
|
||||||
SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable
|
|
||||||
SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction
|
|
||||||
|
|
||||||
for(uint_fast8_t i=0; i<8; i++) {
|
|
||||||
// SGPIO pin 0 outputs slice A bit "i".
|
|
||||||
SGPIO_OUT_MUX_CFG(i) =
|
|
||||||
(0L << 4) | // P_OE_CFG = 0
|
|
||||||
(9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice A
|
|
||||||
SGPIO_MUX_CFG(SGPIO_SLICE_A) =
|
|
||||||
(0L << 12) | // CONCAT_ORDER = 0 (self-loop)
|
|
||||||
(1L << 11) | // CONCAT_ENABLE = 1 (concatenate data)
|
|
||||||
(0L << 9) | // QUALIFIER_SLICE_MODE = X
|
|
||||||
(1L << 7) | // QUALIFIER_PIN_MODE = 1 (SGPIO9)
|
|
||||||
(3L << 5) | // QUALIFIER_MODE = 3 (external SGPIO pin)
|
|
||||||
(0L << 3) | // CLK_SOURCE_SLICE_MODE = X
|
|
||||||
(0L << 1) | // CLK_SOURCE_PIN_MODE = 0 (SGPIO8)
|
|
||||||
(1L << 0); // EXT_CLK_ENABLE = 1, external clock signal (slice)
|
|
||||||
|
|
||||||
SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_A) =
|
|
||||||
(0L << 8) | // INV_QUALIFIER = 0 (use normal qualifier)
|
|
||||||
(3L << 6) | // PARALLEL_MODE = 3 (shift 8 bits per clock)
|
|
||||||
(0L << 4) | // DATA_CAPTURE_MODE = 0 (detect rising edge)
|
|
||||||
(0L << 3) | // INV_OUT_CLK = 0 (normal clock)
|
|
||||||
(1L << 2) | // CLKGEN_MODE = 1 (use external pin clock)
|
|
||||||
(0L << 1) | // CLK_CAPTURE_MODE = 0 (use rising clock edge)
|
|
||||||
(0L << 0); // MATCH_MODE = 0 (do not match data)
|
|
||||||
|
|
||||||
SGPIO_PRESET(SGPIO_SLICE_A) = 0;
|
|
||||||
SGPIO_COUNT(SGPIO_SLICE_A) = 0;
|
|
||||||
SGPIO_POS(SGPIO_SLICE_A) = (0x3L << 8) | (0x3L << 0);
|
|
||||||
SGPIO_REG(SGPIO_SLICE_A) = 0x80808080; // Primary output data register
|
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_A) = 0x80808080; // Shadow output data register
|
|
||||||
|
|
||||||
// Start SGPIO operation by enabling slice clocks.
|
|
||||||
SGPIO_CTRL_ENABLE =
|
|
||||||
(1L << SGPIO_SLICE_A)
|
|
||||||
;
|
|
||||||
|
|
||||||
// LSB goes out first, samples are 0x<Q1><I1><Q0><I0>
|
// LSB goes out first, samples are 0x<Q1><I1><Q0><I0>
|
||||||
volatile uint32_t buffer[] = {
|
volatile uint32_t buffer[] = {
|
||||||
@ -204,8 +42,7 @@ void configure_sgpio_test_tx() {
|
|||||||
};
|
};
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
// Enable codec data stream.
|
sgpio_cpld_stream_enable();
|
||||||
SGPIO_GPIO_OUTREG &= ~(1L << 10);
|
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
while(SGPIO_STATUS_1 == 0);
|
while(SGPIO_STATUS_1 == 0);
|
||||||
@ -214,67 +51,13 @@ void configure_sgpio_test_tx() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void configure_sgpio_test_rx() {
|
void rx_test() {
|
||||||
// Disable all counters during configuration
|
sgpio_configure_for_rx();
|
||||||
SGPIO_CTRL_ENABLE = 0;
|
|
||||||
|
|
||||||
configure_sgpio_pin_functions();
|
|
||||||
|
|
||||||
// Set SGPIO output values.
|
|
||||||
SGPIO_GPIO_OUTREG =
|
|
||||||
(0L << 11) | // direction
|
|
||||||
(1L << 10); // disable
|
|
||||||
|
|
||||||
// Enable SGPIO pin outputs.
|
|
||||||
SGPIO_GPIO_OENREG =
|
|
||||||
(1L << 11) | // direction: RX: data from CPLD
|
|
||||||
(1L << 10) | // disable
|
|
||||||
(0L << 9) | // capture
|
|
||||||
(0L << 8) | // clock
|
|
||||||
0x00; // data: input
|
|
||||||
|
|
||||||
SGPIO_OUT_MUX_CFG( 8) = 0; // SGPIO: Input: clock
|
|
||||||
SGPIO_OUT_MUX_CFG( 9) = 0; // SGPIO: Input: qualifier
|
|
||||||
SGPIO_OUT_MUX_CFG(10) = (0L << 4) | (4L << 0); // GPIO: Output: disable
|
|
||||||
SGPIO_OUT_MUX_CFG(11) = (0L << 4) | (4L << 0); // GPIO: Output: direction
|
|
||||||
|
|
||||||
for(uint_fast8_t i=0; i<8; i++) {
|
|
||||||
SGPIO_OUT_MUX_CFG(i) =
|
|
||||||
(0L << 4) | // P_OE_CFG = 0
|
|
||||||
(9L << 0); // P_OUT_CFG = 9, dout_doutm8a (8-bit mode 8a)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice A
|
|
||||||
SGPIO_MUX_CFG(SGPIO_SLICE_A) =
|
|
||||||
(0L << 12) | // CONCAT_ORDER = X
|
|
||||||
(0L << 11) | // CONCAT_ENABLE = 0 (concatenate data)
|
|
||||||
(0L << 9) | // QUALIFIER_SLICE_MODE = X
|
|
||||||
(1L << 7) | // QUALIFIER_PIN_MODE = 1 (SGPIO9)
|
|
||||||
(3L << 5) | // QUALIFIER_MODE = 3 (external SGPIO pin)
|
|
||||||
(0L << 3) | // CLK_SOURCE_SLICE_MODE = X
|
|
||||||
(0L << 1) | // CLK_SOURCE_PIN_MODE = 0 (SGPIO8)
|
|
||||||
(1L << 0); // EXT_CLK_ENABLE = 1, external clock signal (slice)
|
|
||||||
|
|
||||||
SGPIO_SLICE_MUX_CFG(SGPIO_SLICE_A) =
|
|
||||||
(0L << 8) | // INV_QUALIFIER = 0 (use normal qualifier)
|
|
||||||
(3L << 6) | // PARALLEL_MODE = 3 (shift 8 bits per clock)
|
|
||||||
(0L << 4) | // DATA_CAPTURE_MODE = 0 (detect rising edge)
|
|
||||||
(0L << 3) | // INV_OUT_CLK = X
|
|
||||||
(1L << 2) | // CLKGEN_MODE = 1 (use external pin clock)
|
|
||||||
(0L << 1) | // CLK_CAPTURE_MODE = 0 (use rising clock edge)
|
|
||||||
(0L << 0); // MATCH_MODE = 0 (do not match data)
|
|
||||||
|
|
||||||
SGPIO_PRESET(SGPIO_SLICE_A) = 0;
|
|
||||||
SGPIO_COUNT(SGPIO_SLICE_A) = 0;
|
|
||||||
SGPIO_POS(SGPIO_SLICE_A) = (3 << 8) | (3 << 0);
|
|
||||||
SGPIO_REG(SGPIO_SLICE_A) = 0xCAFEBABE; // Primary output data register
|
|
||||||
SGPIO_REG_SS(SGPIO_SLICE_A) = 0xDEADBEEF; // Shadow output data register
|
|
||||||
|
|
||||||
volatile uint32_t buffer[4096];
|
volatile uint32_t buffer[4096];
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
// Enable codec data stream.
|
sgpio_cpld_stream_enable();
|
||||||
SGPIO_GPIO_OUTREG &= ~(1L << 10);
|
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
while(SGPIO_STATUS_1 == 0);
|
while(SGPIO_STATUS_1 == 0);
|
||||||
@ -289,11 +72,11 @@ int main(void) {
|
|||||||
cpu_clock_init();
|
cpu_clock_init();
|
||||||
ssp1_init();
|
ssp1_init();
|
||||||
|
|
||||||
CGU_BASE_PERIPH_CLK = (CGU_BASE_CLK_AUTOBLOCK
|
CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK
|
||||||
| (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT));
|
| CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||||
|
|
||||||
CGU_BASE_APB1_CLK = (CGU_BASE_CLK_AUTOBLOCK
|
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK
|
||||||
| (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT));
|
| CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||||
|
|
||||||
gpio_set(PORT_LED1_3, PIN_LED1);
|
gpio_set(PORT_LED1_3, PIN_LED1);
|
||||||
|
|
||||||
|
@ -1,4 +1,25 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#
|
||||||
|
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
# Copyright 2012 Benjamin Vernoux <titanmkd@gmail.com>
|
||||||
|
#
|
||||||
|
# This file is part of HackRF.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
BINARY = sgpio_passthrough
|
BINARY = sgpio_passthrough
|
||||||
|
|
||||||
|
@ -29,52 +29,6 @@
|
|||||||
|
|
||||||
#include <hackrf_core.h>
|
#include <hackrf_core.h>
|
||||||
|
|
||||||
void pin_setup(void) {
|
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1 | PIN_LED2 | PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
|
|
||||||
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */
|
|
||||||
scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
|
||||||
scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
|
||||||
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
|
|
||||||
scu_pinmux(SCU_SSP1_SSEL, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable_1v8_power() {
|
|
||||||
gpio_set(PORT_EN1V8, PIN_EN1V8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void release_cpld_jtag_pins() {
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4);
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
|
||||||
scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
|
|
||||||
|
|
||||||
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO;
|
|
||||||
GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK;
|
|
||||||
GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS;
|
|
||||||
GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure_sgpio_pin_functions() {
|
void configure_sgpio_pin_functions() {
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
||||||
scu_pinmux(SCU_PINMUX_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
scu_pinmux(SCU_PINMUX_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
|
||||||
|
@ -27,32 +27,6 @@
|
|||||||
#include "hackrf_core.h"
|
#include "hackrf_core.h"
|
||||||
#include "max2837.h"
|
#include "max2837.h"
|
||||||
|
|
||||||
void pin_setup(void)
|
|
||||||
{
|
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */
|
|
||||||
GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1|PIN_LED2|PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
const uint32_t freq = 2441000000U;
|
const uint32_t freq = 2441000000U;
|
||||||
|
@ -25,37 +25,11 @@
|
|||||||
|
|
||||||
#include "hackrf_core.h"
|
#include "hackrf_core.h"
|
||||||
|
|
||||||
void gpio_setup(void)
|
|
||||||
{
|
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */
|
|
||||||
GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1|PIN_LED2|PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
gpio_setup();
|
pin_setup();
|
||||||
|
|
||||||
gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */
|
gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */
|
||||||
|
|
||||||
|
@ -32,32 +32,6 @@
|
|||||||
volatile u32 g_ulSysTickCount;
|
volatile u32 g_ulSysTickCount;
|
||||||
u32 g_NbCyclePerSecond;
|
u32 g_NbCyclePerSecond;
|
||||||
|
|
||||||
void gpio_setup(void)
|
|
||||||
{
|
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */
|
|
||||||
GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1|PIN_LED2|PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
}
|
|
||||||
|
|
||||||
void systick_setup(void)
|
void systick_setup(void)
|
||||||
{
|
{
|
||||||
u32 systick_reload_val;
|
u32 systick_reload_val;
|
||||||
@ -155,7 +129,7 @@ void sys_tick_handler(void)
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
gpio_setup();
|
pin_setup();
|
||||||
|
|
||||||
gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */
|
gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */
|
||||||
|
|
||||||
|
@ -32,32 +32,6 @@
|
|||||||
volatile u32 g_ulSysTickCount;
|
volatile u32 g_ulSysTickCount;
|
||||||
u32 g_NbCyclePerSecond;
|
u32 g_NbCyclePerSecond;
|
||||||
|
|
||||||
void gpio_setup(void)
|
|
||||||
{
|
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */
|
|
||||||
GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1|PIN_LED2|PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
}
|
|
||||||
|
|
||||||
void systick_setup(void)
|
void systick_setup(void)
|
||||||
{
|
{
|
||||||
u32 systick_reload_val;
|
u32 systick_reload_val;
|
||||||
@ -168,7 +142,7 @@ extern u32 test_nb_instruction_per_sec_1000_nop_asm();
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
gpio_setup();
|
pin_setup();
|
||||||
|
|
||||||
gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */
|
gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */
|
||||||
|
|
||||||
|
@ -32,32 +32,6 @@
|
|||||||
volatile u32 g_ulSysTickCount;
|
volatile u32 g_ulSysTickCount;
|
||||||
u32 g_NbCyclePerSecond;
|
u32 g_NbCyclePerSecond;
|
||||||
|
|
||||||
void gpio_setup(void)
|
|
||||||
{
|
|
||||||
/* Configure SCU Pin Mux as GPIO */
|
|
||||||
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST);
|
|
||||||
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST);
|
|
||||||
|
|
||||||
/* Configure all GPIO as Input (safe state) */
|
|
||||||
GPIO0_DIR = 0;
|
|
||||||
GPIO1_DIR = 0;
|
|
||||||
GPIO2_DIR = 0;
|
|
||||||
GPIO3_DIR = 0;
|
|
||||||
GPIO4_DIR = 0;
|
|
||||||
GPIO5_DIR = 0;
|
|
||||||
GPIO6_DIR = 0;
|
|
||||||
GPIO7_DIR = 0;
|
|
||||||
|
|
||||||
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
|
|
||||||
GPIO2_DIR |= (PIN_LED1|PIN_LED2|PIN_LED3);
|
|
||||||
|
|
||||||
/* GPIO3[6] on P6_10 as output. */
|
|
||||||
GPIO3_DIR |= PIN_EN1V8;
|
|
||||||
}
|
|
||||||
|
|
||||||
void systick_setup(void)
|
void systick_setup(void)
|
||||||
{
|
{
|
||||||
u32 systick_reload_val;
|
u32 systick_reload_val;
|
||||||
@ -168,7 +142,7 @@ extern u32 test_nb_instruction_per_sec_1000_nop_asm();
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
gpio_setup();
|
pin_setup();
|
||||||
|
|
||||||
gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */
|
gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */
|
||||||
|
|
||||||
|
39
firmware/usb_performance/Makefile
Normal file
39
firmware/usb_performance/Makefile
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#
|
||||||
|
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
#
|
||||||
|
# This file is part of HackRF.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
BINARY = usb_performance
|
||||||
|
|
||||||
|
SRC = $(BINARY).c \
|
||||||
|
usb.c \
|
||||||
|
usb_request.c \
|
||||||
|
usb_standard_request.c \
|
||||||
|
usb_descriptor.c \
|
||||||
|
../common/fault_handler.c \
|
||||||
|
../common/hackrf_core.c \
|
||||||
|
../common/sgpio.c \
|
||||||
|
../common/si5351c.c \
|
||||||
|
../common/max2837.c \
|
||||||
|
../common/max5864.c \
|
||||||
|
../common/rffc5071.c
|
||||||
|
|
||||||
|
LDSCRIPT = ../common/LPC4330_M4_ram_only.ld
|
||||||
|
include ../common/Makefile_inc.mk
|
652
firmware/usb_performance/usb.c
Normal file
652
firmware/usb_performance/usb.c
Normal file
@ -0,0 +1,652 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "usb.h"
|
||||||
|
#include "usb_type.h"
|
||||||
|
#include "usb_standard_request.h"
|
||||||
|
|
||||||
|
#include <libopencm3/lpc43xx/creg.h>
|
||||||
|
#include <libopencm3/lpc43xx/nvic.h>
|
||||||
|
#include <libopencm3/lpc43xx/rgu.h>
|
||||||
|
#include <libopencm3/lpc43xx/usb.h>
|
||||||
|
|
||||||
|
usb_device_t* usb_device_usb0 = 0;
|
||||||
|
|
||||||
|
usb_queue_head_t usb_qh[12] ATTR_ALIGNED(2048);
|
||||||
|
usb_transfer_descriptor_t usb_td[12] ATTR_ALIGNED(64);
|
||||||
|
|
||||||
|
#define USB_QH_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1))
|
||||||
|
#define USB_TD_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1))
|
||||||
|
|
||||||
|
usb_queue_head_t* usb_queue_head(
|
||||||
|
const uint_fast8_t endpoint_address
|
||||||
|
) {
|
||||||
|
return &usb_qh[USB_QH_INDEX(endpoint_address)];
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_transfer_descriptor_t* usb_transfer_descriptor(
|
||||||
|
const uint_fast8_t endpoint_address
|
||||||
|
) {
|
||||||
|
return &usb_td[USB_TD_INDEX(endpoint_address)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static usb_endpoint_t* usb_endpoint_from_address(
|
||||||
|
const uint_fast8_t endpoint_address
|
||||||
|
) {
|
||||||
|
return (usb_endpoint_t*)usb_queue_head(endpoint_address)->_reserved_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint_fast8_t usb_endpoint_address(
|
||||||
|
const usb_transfer_direction_t direction,
|
||||||
|
const uint_fast8_t number
|
||||||
|
) {
|
||||||
|
return ((direction == USB_TRANSFER_DIRECTION_IN) ? 0x80 : 0x00) + number;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool usb_endpoint_is_in(const uint_fast8_t endpoint_address) {
|
||||||
|
return (endpoint_address & 0x80) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint_fast8_t usb_endpoint_number(const uint_fast8_t endpoint_address) {
|
||||||
|
return (endpoint_address & 0xF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_peripheral_reset() {
|
||||||
|
RESET_CTRL0 = RESET_CTRL0_USB0_RST;
|
||||||
|
RESET_CTRL0 = 0;
|
||||||
|
|
||||||
|
while( (RESET_ACTIVE_STATUS0 & RESET_CTRL0_USB0_RST) == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_phy_enable() {
|
||||||
|
CREG_CREG0 &= ~CREG_CREG0_USB0PHY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_clear_pending_interrupts(const uint32_t mask) {
|
||||||
|
USB0_ENDPTNAK = mask;
|
||||||
|
USB0_ENDPTNAKEN = mask;
|
||||||
|
USB0_USBSTS_D = mask;
|
||||||
|
USB0_ENDPTSETUPSTAT = USB0_ENDPTSETUPSTAT & mask;
|
||||||
|
USB0_ENDPTCOMPLETE = USB0_ENDPTCOMPLETE & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_clear_all_pending_interrupts() {
|
||||||
|
usb_clear_pending_interrupts(0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_wait_for_endpoint_priming_to_finish(const uint32_t mask) {
|
||||||
|
// Wait until controller has parsed new transfer descriptors and prepared
|
||||||
|
// receive buffers.
|
||||||
|
while( USB0_ENDPTPRIME & mask );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_flush_endpoints(const uint32_t mask) {
|
||||||
|
// Clear any primed buffers. If a packet is in progress, that transfer
|
||||||
|
// will continue until completion.
|
||||||
|
USB0_ENDPTFLUSH = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_wait_for_endpoint_flushing_to_finish(const uint32_t mask) {
|
||||||
|
// Wait until controller has flushed all endpoints / cleared any primed
|
||||||
|
// buffers.
|
||||||
|
while( USB0_ENDPTFLUSH & mask );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_flush_primed_endpoints(const uint32_t mask) {
|
||||||
|
usb_wait_for_endpoint_priming_to_finish(mask);
|
||||||
|
usb_flush_endpoints(mask);
|
||||||
|
usb_wait_for_endpoint_flushing_to_finish(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_flush_all_primed_endpoints() {
|
||||||
|
usb_flush_primed_endpoints(0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_endpoint_set_type(
|
||||||
|
const usb_endpoint_t* const endpoint,
|
||||||
|
const usb_transfer_type_t transfer_type
|
||||||
|
) {
|
||||||
|
// NOTE: UM10503 section 23.6.24 "Endpoint 1 to 5 control registers" says
|
||||||
|
// that the disabled side of an endpoint must be set to a non-control type
|
||||||
|
// (e.g. bulk, interrupt, or iso).
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
USB0_ENDPTCTRL(endpoint_number)
|
||||||
|
= ( USB0_ENDPTCTRL(endpoint_number)
|
||||||
|
& ~(USB0_ENDPTCTRL_TXT1_0_MASK | USB0_ENDPTCTRL_RXT_MASK)
|
||||||
|
)
|
||||||
|
| ( USB0_ENDPTCTRL_TXT1_0(transfer_type)
|
||||||
|
| USB0_ENDPTCTRL_RXT(transfer_type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_endpoint_enable(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||||
|
USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_TXE | USB0_ENDPTCTRL_TXR);
|
||||||
|
} else {
|
||||||
|
USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_RXE | USB0_ENDPTCTRL_RXR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_endpoint_clear_pending_interrupts(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||||
|
usb_clear_pending_interrupts(USB0_ENDPTCOMPLETE_ETCE(1 << endpoint_number));
|
||||||
|
} else {
|
||||||
|
usb_clear_pending_interrupts(USB0_ENDPTCOMPLETE_ERCE(1 << endpoint_number));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_endpoint_disable(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||||
|
USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_TXE);
|
||||||
|
} else {
|
||||||
|
USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_RXE);
|
||||||
|
}
|
||||||
|
usb_endpoint_clear_pending_interrupts(endpoint);
|
||||||
|
usb_endpoint_flush(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_endpoint_prime(
|
||||||
|
const usb_endpoint_t* const endpoint,
|
||||||
|
usb_transfer_descriptor_t* const first_td
|
||||||
|
) {
|
||||||
|
usb_queue_head_t* const qh = usb_queue_head(endpoint->address);
|
||||||
|
|
||||||
|
qh->next_dtd_pointer = first_td;
|
||||||
|
qh->total_bytes
|
||||||
|
&= ~( USB_TD_DTD_TOKEN_STATUS_ACTIVE
|
||||||
|
| USB_TD_DTD_TOKEN_STATUS_HALTED
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||||
|
USB0_ENDPTPRIME = USB0_ENDPTPRIME_PETB(1 << endpoint_number);
|
||||||
|
} else {
|
||||||
|
USB0_ENDPTPRIME = USB0_ENDPTPRIME_PERB(1 << endpoint_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
static bool usb_endpoint_is_priming(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||||
|
return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PETB(1 << endpoint_number);
|
||||||
|
} else {
|
||||||
|
return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PERB(1 << endpoint_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void usb_endpoint_flush(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||||
|
usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FETB(1 << endpoint_number));
|
||||||
|
} else {
|
||||||
|
usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FERB(1 << endpoint_number));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
static bool usb_endpoint_is_flushing(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||||
|
return USB0_ENDPTFLUSH & USB0_ENDPTFLUSH_FETB(1 << endpoint_number);
|
||||||
|
} else {
|
||||||
|
return USB0_ENDPTFLUSH & USB0_ENDPTFLUSH_FERB(1 << endpoint_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
bool usb_endpoint_is_ready(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||||
|
return USB0_ENDPTSTAT & USB0_ENDPTSTAT_ETBR(1 << endpoint_number);
|
||||||
|
} else {
|
||||||
|
return USB0_ENDPTSTAT & USB0_ENDPTSTAT_ERBR(1 << endpoint_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usb_endpoint_is_complete(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||||
|
return USB0_ENDPTCOMPLETE & USB0_ENDPTCOMPLETE_ETCE(1 << endpoint_number);
|
||||||
|
} else {
|
||||||
|
return USB0_ENDPTCOMPLETE & USB0_ENDPTCOMPLETE_ERCE(1 << endpoint_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_endpoint_stall(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
// Endpoint is to be stalled as a pair -- both OUT and IN.
|
||||||
|
// See UM10503 section 23.10.5.2 "Stalling"
|
||||||
|
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||||
|
USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_RXS | USB0_ENDPTCTRL_TXS);
|
||||||
|
|
||||||
|
// TODO: Also need to reset data toggle in both directions?
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_controller_run() {
|
||||||
|
USB0_USBCMD_D |= USB0_USBCMD_D_RS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_controller_stop() {
|
||||||
|
USB0_USBCMD_D &= ~USB0_USBCMD_D_RS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint_fast8_t usb_controller_is_resetting() {
|
||||||
|
return (USB0_USBCMD_D & USB0_USBCMD_D_RST) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_controller_set_device_mode() {
|
||||||
|
// Set USB0 peripheral mode
|
||||||
|
USB0_USBMODE_D = USB0_USBMODE_D_CM1_0(2);
|
||||||
|
|
||||||
|
// Set device-related OTG flags
|
||||||
|
// OTG termination: controls pull-down on USB_DM
|
||||||
|
// VBUS_Discharge: VBUS discharges through resistor
|
||||||
|
USB0_OTGSC = USB0_OTGSC_OT | USB0_OTGSC_VD;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_speed_t usb_speed(
|
||||||
|
const usb_device_t* const device
|
||||||
|
) {
|
||||||
|
if( device == usb_device_usb0 ) {
|
||||||
|
switch( USB0_PORTSC1_D & USB0_PORTSC1_D_PSPD_MASK ) {
|
||||||
|
case USB0_PORTSC1_D_PSPD(0):
|
||||||
|
return USB_SPEED_FULL;
|
||||||
|
|
||||||
|
case USB0_PORTSC1_D_PSPD(2):
|
||||||
|
return USB_SPEED_HIGH;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// TODO: What to do/return here? Is this even possible?
|
||||||
|
return USB_SPEED_FULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: This should not be possible with a more class-like
|
||||||
|
// implementation.
|
||||||
|
return USB_SPEED_FULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_clear_status(const uint32_t status) {
|
||||||
|
USB0_USBSTS_D = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t usb_get_status() {
|
||||||
|
// Mask status flags with enabled flag interrupts.
|
||||||
|
const uint32_t status = USB0_USBSTS_D & USB0_USBINTR_D;
|
||||||
|
|
||||||
|
// Clear flags that were just read, leaving alone any flags that
|
||||||
|
// were just set (after the read). It's important to read and
|
||||||
|
// reset flags atomically! :-)
|
||||||
|
usb_clear_status(status);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_clear_endpoint_setup_status(const uint32_t endpoint_setup_status) {
|
||||||
|
USB0_ENDPTSETUPSTAT = endpoint_setup_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t usb_get_endpoint_setup_status() {
|
||||||
|
return USB0_ENDPTSETUPSTAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_clear_endpoint_complete(const uint32_t endpoint_complete) {
|
||||||
|
USB0_ENDPTCOMPLETE = endpoint_complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t usb_get_endpoint_complete() {
|
||||||
|
return USB0_ENDPTCOMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_disable_all_endpoints() {
|
||||||
|
// Endpoint 0 is always enabled. TODO: So why set ENDPTCTRL0?
|
||||||
|
USB0_ENDPTCTRL0 &= ~(USB0_ENDPTCTRL0_RXE | USB0_ENDPTCTRL0_TXE);
|
||||||
|
USB0_ENDPTCTRL1 &= ~(USB0_ENDPTCTRL1_RXE | USB0_ENDPTCTRL1_TXE);
|
||||||
|
USB0_ENDPTCTRL2 &= ~(USB0_ENDPTCTRL2_RXE | USB0_ENDPTCTRL2_TXE);
|
||||||
|
USB0_ENDPTCTRL3 &= ~(USB0_ENDPTCTRL3_RXE | USB0_ENDPTCTRL3_TXE);
|
||||||
|
USB0_ENDPTCTRL4 &= ~(USB0_ENDPTCTRL4_RXE | USB0_ENDPTCTRL4_TXE);
|
||||||
|
USB0_ENDPTCTRL5 &= ~(USB0_ENDPTCTRL5_RXE | USB0_ENDPTCTRL5_TXE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_set_address_immediate(
|
||||||
|
const usb_device_t* const device,
|
||||||
|
const uint_fast8_t address
|
||||||
|
) {
|
||||||
|
if( device == usb_device_usb0 ) {
|
||||||
|
USB0_DEVICEADDR = USB0_DEVICEADDR_USBADR(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_set_address_deferred(
|
||||||
|
const usb_device_t* const device,
|
||||||
|
const uint_fast8_t address
|
||||||
|
) {
|
||||||
|
if( device == usb_device_usb0 ) {
|
||||||
|
USB0_DEVICEADDR
|
||||||
|
= USB0_DEVICEADDR_USBADR(address)
|
||||||
|
| USB0_DEVICEADDR_USBADRA
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_reset_all_endpoints() {
|
||||||
|
usb_disable_all_endpoints();
|
||||||
|
usb_clear_all_pending_interrupts();
|
||||||
|
usb_flush_all_primed_endpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_controller_reset() {
|
||||||
|
// TODO: Good to disable some USB interrupts to avoid priming new
|
||||||
|
// new endpoints before the controller is reset?
|
||||||
|
usb_reset_all_endpoints();
|
||||||
|
usb_controller_stop();
|
||||||
|
|
||||||
|
// Reset controller. Resets internal pipelines, timers, counters, state
|
||||||
|
// machines to initial values. Not recommended when device is in attached
|
||||||
|
// state -- effect on attached host is undefined. Detach first by flushing
|
||||||
|
// all primed endpoints and stopping controller.
|
||||||
|
USB0_USBCMD_D = USB0_USBCMD_D_RST;
|
||||||
|
|
||||||
|
while( usb_controller_is_resetting() );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_bus_reset(usb_device_t* const device) {
|
||||||
|
// According to UM10503 v1.4 section 23.10.3 "Bus reset":
|
||||||
|
usb_reset_all_endpoints();
|
||||||
|
usb_set_address_immediate(device, 0);
|
||||||
|
usb_set_configuration(device, 0);
|
||||||
|
|
||||||
|
// TODO: Enable endpoint 0, which might not actually be necessary,
|
||||||
|
// as the datasheet claims it can't be disabled.
|
||||||
|
|
||||||
|
//wait_ms(3);
|
||||||
|
//
|
||||||
|
//if( USB0_PORTSC1 & USB0_PORTSC1_PR ) {
|
||||||
|
// // Port still is in the reset state.
|
||||||
|
//} else {
|
||||||
|
// usb_hardware_reset();
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_interrupt_enable(
|
||||||
|
usb_device_t* const device
|
||||||
|
) {
|
||||||
|
if( device == usb_device_usb0 ) {
|
||||||
|
nvic_enable_irq(NVIC_M4_USB0_IRQ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_device_init(
|
||||||
|
const uint_fast8_t device_ordinal,
|
||||||
|
usb_device_t* const device
|
||||||
|
) {
|
||||||
|
if( device_ordinal == 0 ) {
|
||||||
|
usb_device_usb0 = device;
|
||||||
|
|
||||||
|
usb_phy_enable();
|
||||||
|
usb_controller_reset();
|
||||||
|
usb_controller_set_device_mode();
|
||||||
|
|
||||||
|
// Set interrupt threshold interval to 0
|
||||||
|
USB0_USBCMD_D &= ~USB0_USBCMD_D_ITC_MASK;
|
||||||
|
|
||||||
|
// Configure endpoint list address
|
||||||
|
USB0_ENDPOINTLISTADDR = (uint32_t)usb_qh;
|
||||||
|
|
||||||
|
// Enable interrupts
|
||||||
|
USB0_USBINTR_D =
|
||||||
|
USB0_USBINTR_D_UE
|
||||||
|
| USB0_USBINTR_D_UEE
|
||||||
|
| USB0_USBINTR_D_PCE
|
||||||
|
| USB0_USBINTR_D_URE
|
||||||
|
//| USB0_USBINTR_D_SRE
|
||||||
|
| USB0_USBINTR_D_SLE
|
||||||
|
//| USB0_USBINTR_D_NAKE
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_run(
|
||||||
|
usb_device_t* const device
|
||||||
|
) {
|
||||||
|
usb_interrupt_enable(device);
|
||||||
|
usb_controller_run(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_setup(usb_setup_t* const dst, const volatile uint8_t* const src) {
|
||||||
|
dst->request_type = src[0];
|
||||||
|
dst->request = src[1];
|
||||||
|
dst->value_l = src[2];
|
||||||
|
dst->value_h = src[3];
|
||||||
|
dst->index_l = src[4];
|
||||||
|
dst->index_h = src[5];
|
||||||
|
dst->length_l = src[6];
|
||||||
|
dst->length_h = src[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_endpoint_init(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
usb_endpoint_flush(endpoint);
|
||||||
|
|
||||||
|
uint_fast16_t max_packet_size = endpoint->device->descriptor[7];
|
||||||
|
usb_transfer_type_t transfer_type = USB_TRANSFER_TYPE_CONTROL;
|
||||||
|
const uint8_t* const endpoint_descriptor = usb_endpoint_descriptor(endpoint);
|
||||||
|
if( endpoint_descriptor ) {
|
||||||
|
max_packet_size = usb_endpoint_descriptor_max_packet_size(endpoint_descriptor);
|
||||||
|
transfer_type = usb_endpoint_descriptor_transfer_type(endpoint_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: There are more capabilities to adjust based on the endpoint
|
||||||
|
// descriptor.
|
||||||
|
usb_queue_head_t* const qh = usb_queue_head(endpoint->address);
|
||||||
|
qh->capabilities
|
||||||
|
= USB_QH_CAPABILITIES_MULT(0)
|
||||||
|
| USB_QH_CAPABILITIES_ZLT
|
||||||
|
| USB_QH_CAPABILITIES_MPL(max_packet_size)
|
||||||
|
| ((transfer_type == USB_TRANSFER_TYPE_CONTROL) ? USB_QH_CAPABILITIES_IOS : 0)
|
||||||
|
;
|
||||||
|
qh->current_dtd_pointer = 0;
|
||||||
|
qh->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
||||||
|
qh->total_bytes
|
||||||
|
= USB_TD_DTD_TOKEN_TOTAL_BYTES(0)
|
||||||
|
| USB_TD_DTD_TOKEN_MULTO(0)
|
||||||
|
;
|
||||||
|
qh->buffer_pointer_page[0] = 0;
|
||||||
|
qh->buffer_pointer_page[1] = 0;
|
||||||
|
qh->buffer_pointer_page[2] = 0;
|
||||||
|
qh->buffer_pointer_page[3] = 0;
|
||||||
|
qh->buffer_pointer_page[4] = 0;
|
||||||
|
|
||||||
|
// This is how we look up an endpoint structure from an endpoint address:
|
||||||
|
qh->_reserved_0 = (uint32_t)endpoint;
|
||||||
|
|
||||||
|
// TODO: Should NAK be enabled? I'm kinda squishy on this...
|
||||||
|
//USB0_ENDPTNAKEN |=
|
||||||
|
// USB0_ENDPTNAKEN_EPRNE(1 << endpoint_out->number);
|
||||||
|
|
||||||
|
usb_endpoint_set_type(endpoint, transfer_type);
|
||||||
|
|
||||||
|
usb_endpoint_enable(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_endpoint_schedule(
|
||||||
|
const usb_endpoint_t* const endpoint,
|
||||||
|
void* const data,
|
||||||
|
const uint32_t maximum_length
|
||||||
|
) {
|
||||||
|
usb_transfer_descriptor_t* const td = usb_transfer_descriptor(endpoint->address);
|
||||||
|
|
||||||
|
// Ensure that endpoint is ready to be primed.
|
||||||
|
// It may have been flushed due to an aborted transaction.
|
||||||
|
// TODO: This should be preceded by a flush?
|
||||||
|
while( usb_endpoint_is_ready(endpoint) );
|
||||||
|
|
||||||
|
// Configure a transfer.
|
||||||
|
td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
||||||
|
td->total_bytes =
|
||||||
|
USB_TD_DTD_TOKEN_TOTAL_BYTES(maximum_length)
|
||||||
|
| USB_TD_DTD_TOKEN_IOC
|
||||||
|
| USB_TD_DTD_TOKEN_MULTO(0)
|
||||||
|
| USB_TD_DTD_TOKEN_STATUS_ACTIVE
|
||||||
|
;
|
||||||
|
td->buffer_pointer_page[0] = (uint32_t)data;
|
||||||
|
td->buffer_pointer_page[1] = ((uint32_t)data + 0x1000) & 0xfffff000;
|
||||||
|
td->buffer_pointer_page[2] = ((uint32_t)data + 0x2000) & 0xfffff000;
|
||||||
|
td->buffer_pointer_page[3] = ((uint32_t)data + 0x3000) & 0xfffff000;
|
||||||
|
td->buffer_pointer_page[4] = ((uint32_t)data + 0x4000) & 0xfffff000;
|
||||||
|
|
||||||
|
usb_endpoint_prime(endpoint, td);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_endpoint_schedule_ack(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
usb_endpoint_schedule(endpoint, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_check_for_setup_events() {
|
||||||
|
const uint32_t endptsetupstat = usb_get_endpoint_setup_status();
|
||||||
|
if( endptsetupstat ) {
|
||||||
|
for( uint_fast8_t i=0; i<6; i++ ) {
|
||||||
|
const uint32_t endptsetupstat_bit = USB0_ENDPTSETUPSTAT_ENDPTSETUPSTAT(1 << i);
|
||||||
|
if( endptsetupstat & endptsetupstat_bit ) {
|
||||||
|
usb_endpoint_t* const endpoint =
|
||||||
|
usb_endpoint_from_address(
|
||||||
|
usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i)
|
||||||
|
);
|
||||||
|
if( endpoint && endpoint->setup_complete ) {
|
||||||
|
copy_setup(&endpoint->setup, usb_queue_head(endpoint->address)->setup);
|
||||||
|
usb_clear_endpoint_setup_status(endptsetupstat_bit);
|
||||||
|
endpoint->setup_complete(endpoint);
|
||||||
|
} else {
|
||||||
|
usb_clear_endpoint_setup_status(endptsetupstat_bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_check_for_transfer_events() {
|
||||||
|
const uint32_t endptcomplete = usb_get_endpoint_complete();
|
||||||
|
if( endptcomplete ) {
|
||||||
|
for( uint_fast8_t i=0; i<6; i++ ) {
|
||||||
|
|
||||||
|
const uint32_t endptcomplete_out_bit = USB0_ENDPTCOMPLETE_ERCE(1 << i);
|
||||||
|
if( endptcomplete & endptcomplete_out_bit ) {
|
||||||
|
usb_clear_endpoint_complete(endptcomplete_out_bit);
|
||||||
|
usb_endpoint_t* const endpoint =
|
||||||
|
usb_endpoint_from_address(
|
||||||
|
usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i)
|
||||||
|
);
|
||||||
|
if( endpoint && endpoint->transfer_complete ) {
|
||||||
|
endpoint->transfer_complete(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t endptcomplete_in_bit = USB0_ENDPTCOMPLETE_ETCE(1 << i);
|
||||||
|
if( endptcomplete & endptcomplete_in_bit ) {
|
||||||
|
usb_clear_endpoint_complete(endptcomplete_in_bit);
|
||||||
|
usb_endpoint_t* const endpoint =
|
||||||
|
usb_endpoint_from_address(
|
||||||
|
usb_endpoint_address(USB_TRANSFER_DIRECTION_IN, i)
|
||||||
|
);
|
||||||
|
if( endpoint && endpoint->transfer_complete ) {
|
||||||
|
endpoint->transfer_complete(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb0_irqhandler() {
|
||||||
|
const uint32_t status = usb_get_status();
|
||||||
|
|
||||||
|
if( status == 0 ) {
|
||||||
|
// Nothing to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status & USB0_USBSTS_D_UI ) {
|
||||||
|
// USB:
|
||||||
|
// - Completed transaction transfer descriptor has IOC set.
|
||||||
|
// - Short packet detected.
|
||||||
|
// - SETUP packet received.
|
||||||
|
|
||||||
|
usb_check_for_setup_events();
|
||||||
|
usb_check_for_transfer_events();
|
||||||
|
|
||||||
|
// TODO: Reset ignored ENDPTSETUPSTAT and ENDPTCOMPLETE flags?
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status & USB0_USBSTS_D_SRI ) {
|
||||||
|
// Start Of Frame received.
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status & USB0_USBSTS_D_PCI ) {
|
||||||
|
// Port change detect:
|
||||||
|
// Port controller entered full- or high-speed operational state.
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status & USB0_USBSTS_D_SLI ) {
|
||||||
|
// Device controller suspend.
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status & USB0_USBSTS_D_URI ) {
|
||||||
|
// USB reset received.
|
||||||
|
usb_bus_reset(usb_device_usb0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status & USB0_USBSTS_D_UEI ) {
|
||||||
|
// USB error:
|
||||||
|
// Completion of a USB transaction resulted in an error condition.
|
||||||
|
// Set along with USBINT if the TD on which the error interrupt
|
||||||
|
// occurred also had its interrupt on complete (IOC) bit set.
|
||||||
|
// The device controller detects resume signalling only.
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status & USB0_USBSTS_D_NAKI ) {
|
||||||
|
// Both the TX/RX endpoint NAK bit and corresponding TX/RX endpoint
|
||||||
|
// NAK enable bit are set.
|
||||||
|
}
|
||||||
|
}
|
103
firmware/usb_performance/usb.h
Normal file
103
firmware/usb_performance/usb.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __USB_H__
|
||||||
|
#define __USB_H__
|
||||||
|
|
||||||
|
// TODO: Refactor to support high performance operations without having to
|
||||||
|
// expose usb_transfer_descriptor_t. Or usb_endpoint_prime(). Or, or, or...
|
||||||
|
#include <libopencm3/lpc43xx/usb.h>
|
||||||
|
|
||||||
|
#include "usb_type.h"
|
||||||
|
|
||||||
|
#define ATTR_ALIGNED(x) __attribute__ ((aligned(x)))
|
||||||
|
#define ATTR_SECTION(x) __attribute__ ((section(x)))
|
||||||
|
|
||||||
|
extern bool usb_set_configuration(
|
||||||
|
usb_device_t* const device,
|
||||||
|
const uint_fast8_t configuration_number
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_peripheral_reset();
|
||||||
|
|
||||||
|
void usb_device_init(
|
||||||
|
const uint_fast8_t device_ordinal,
|
||||||
|
usb_device_t* const device
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_run(
|
||||||
|
usb_device_t* const device
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_run_tasks(
|
||||||
|
const usb_device_t* const device
|
||||||
|
);
|
||||||
|
|
||||||
|
usb_speed_t usb_speed(
|
||||||
|
const usb_device_t* const device
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_set_address_immediate(
|
||||||
|
const usb_device_t* const device,
|
||||||
|
const uint_fast8_t address
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_set_address_deferred(
|
||||||
|
const usb_device_t* const device,
|
||||||
|
const uint_fast8_t address
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_endpoint_init(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_endpoint_schedule(
|
||||||
|
const usb_endpoint_t* const endpoint,
|
||||||
|
void* const data,
|
||||||
|
const uint32_t maximum_length
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_endpoint_schedule_ack(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_endpoint_stall(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_endpoint_disable(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_endpoint_flush(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
bool usb_endpoint_is_ready(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_endpoint_prime(
|
||||||
|
const usb_endpoint_t* const endpoint,
|
||||||
|
usb_transfer_descriptor_t* const first_td
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif//__USB_H__
|
190
firmware/usb_performance/usb_descriptor.c
Normal file
190
firmware/usb_performance/usb_descriptor.c
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "usb_type.h"
|
||||||
|
|
||||||
|
#define USB_VENDOR_ID (0x1D50)
|
||||||
|
#define USB_PRODUCT_ID (0x604B)
|
||||||
|
|
||||||
|
#define USB_WORD(x) (x & 0xFF), ((x >> 8) & 0xFF)
|
||||||
|
|
||||||
|
#define USB_MAX_PACKET0 (64)
|
||||||
|
#define USB_MAX_PACKET_BULK_FS (64)
|
||||||
|
#define USB_MAX_PACKET_BULK_HS (512)
|
||||||
|
|
||||||
|
#define USB_BULK_IN_EP_ADDR (0x81)
|
||||||
|
#define USB_BULK_OUT_EP_ADDR (0x02)
|
||||||
|
|
||||||
|
#define USB_STRING_LANGID (0x0409)
|
||||||
|
|
||||||
|
uint8_t usb_descriptor_device[] = {
|
||||||
|
18, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_DEVICE, // bDescriptorType
|
||||||
|
USB_WORD(0x0200), // bcdUSB
|
||||||
|
0x00, // bDeviceClass
|
||||||
|
0x00, // bDeviceSubClass
|
||||||
|
0x00, // bDeviceProtocol
|
||||||
|
USB_MAX_PACKET0, // bMaxPacketSize0
|
||||||
|
USB_WORD(USB_VENDOR_ID), // idVendor
|
||||||
|
USB_WORD(USB_PRODUCT_ID), // idProduct
|
||||||
|
USB_WORD(0x0100), // bcdDevice
|
||||||
|
0x01, // iManufacturer
|
||||||
|
0x02, // iProduct
|
||||||
|
0x00, // iSerialNumber
|
||||||
|
0x01 // bNumConfigurations
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t usb_descriptor_device_qualifier[] = {
|
||||||
|
10, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, // bDescriptorType
|
||||||
|
USB_WORD(0x0200), // bcdUSB
|
||||||
|
0x00, // bDeviceClass
|
||||||
|
0x00, // bDeviceSubClass
|
||||||
|
0x00, // bDeviceProtocol
|
||||||
|
64, // bMaxPacketSize0
|
||||||
|
0x01, // bNumOtherSpeedConfigurations
|
||||||
|
0x00 // bReserved
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t usb_descriptor_configuration_full_speed[] = {
|
||||||
|
9, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
|
||||||
|
USB_WORD(32), // wTotalLength
|
||||||
|
0x01, // bNumInterfaces
|
||||||
|
0x01, // bConfigurationValue
|
||||||
|
0x00, // iConfiguration
|
||||||
|
0x80, // bmAttributes: USB-powered
|
||||||
|
250, // bMaxPower: 500mA
|
||||||
|
|
||||||
|
9, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType
|
||||||
|
0x00, // bInterfaceNumber
|
||||||
|
0x00, // bAlternateSetting
|
||||||
|
0x02, // bNumEndpoints
|
||||||
|
0xFF, // bInterfaceClass: vendor-specific
|
||||||
|
0xFF, // bInterfaceSubClass
|
||||||
|
0xFF, // bInterfaceProtocol: vendor-specific
|
||||||
|
0x00, // iInterface
|
||||||
|
|
||||||
|
7, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||||
|
USB_BULK_IN_EP_ADDR, // bEndpointAddress
|
||||||
|
0x02, // bmAttributes: BULK
|
||||||
|
USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize
|
||||||
|
0x00, // bInterval: no NAK
|
||||||
|
|
||||||
|
7, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||||
|
USB_BULK_OUT_EP_ADDR, // bEndpointAddress
|
||||||
|
0x02, // bmAttributes: BULK
|
||||||
|
USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize
|
||||||
|
0x00, // bInterval: no NAK
|
||||||
|
|
||||||
|
0, // TERMINATOR
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t usb_descriptor_configuration_high_speed[] = {
|
||||||
|
9, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
|
||||||
|
USB_WORD(32), // wTotalLength
|
||||||
|
0x01, // bNumInterfaces
|
||||||
|
0x01, // bConfigurationValue
|
||||||
|
0x00, // iConfiguration
|
||||||
|
0x80, // bmAttributes: USB-powered
|
||||||
|
250, // bMaxPower: 500mA
|
||||||
|
|
||||||
|
9, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType
|
||||||
|
0x00, // bInterfaceNumber
|
||||||
|
0x00, // bAlternateSetting
|
||||||
|
0x02, // bNumEndpoints
|
||||||
|
0xFF, // bInterfaceClass: vendor-specific
|
||||||
|
0xFF, // bInterfaceSubClass
|
||||||
|
0xFF, // bInterfaceProtocol: vendor-specific
|
||||||
|
0x00, // iInterface
|
||||||
|
|
||||||
|
7, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||||
|
USB_BULK_IN_EP_ADDR, // bEndpointAddress
|
||||||
|
0x02, // bmAttributes: BULK
|
||||||
|
USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize
|
||||||
|
0x00, // bInterval: no NAK
|
||||||
|
|
||||||
|
7, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType
|
||||||
|
USB_BULK_OUT_EP_ADDR, // bEndpointAddress
|
||||||
|
0x02, // bmAttributes: BULK
|
||||||
|
USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize
|
||||||
|
0x00, // bInterval: no NAK
|
||||||
|
|
||||||
|
0, // TERMINATOR
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t usb_descriptor_string_languages[] = {
|
||||||
|
0x04, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||||
|
USB_WORD(USB_STRING_LANGID), // wLANGID
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t usb_descriptor_string_manufacturer[] = {
|
||||||
|
40, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||||
|
'G', 0x00,
|
||||||
|
'r', 0x00,
|
||||||
|
'e', 0x00,
|
||||||
|
'a', 0x00,
|
||||||
|
't', 0x00,
|
||||||
|
' ', 0x00,
|
||||||
|
'S', 0x00,
|
||||||
|
'c', 0x00,
|
||||||
|
'o', 0x00,
|
||||||
|
't', 0x00,
|
||||||
|
't', 0x00,
|
||||||
|
' ', 0x00,
|
||||||
|
'G', 0x00,
|
||||||
|
'a', 0x00,
|
||||||
|
'd', 0x00,
|
||||||
|
'g', 0x00,
|
||||||
|
'e', 0x00,
|
||||||
|
't', 0x00,
|
||||||
|
's', 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t usb_descriptor_string_product[] = {
|
||||||
|
14, // bLength
|
||||||
|
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
|
||||||
|
'H', 0x00,
|
||||||
|
'a', 0x00,
|
||||||
|
'c', 0x00,
|
||||||
|
'k', 0x00,
|
||||||
|
'R', 0x00,
|
||||||
|
'F', 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t* const usb_descriptor_strings[] = {
|
||||||
|
usb_descriptor_string_languages,
|
||||||
|
usb_descriptor_string_manufacturer,
|
||||||
|
usb_descriptor_string_product,
|
||||||
|
|
||||||
|
0, // TERMINATOR
|
||||||
|
};
|
33
firmware/usb_performance/usb_descriptor.h
Normal file
33
firmware/usb_performance/usb_descriptor.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern uint8_t usb_descriptor_device[];
|
||||||
|
extern uint8_t usb_descriptor_device_qualifier[];
|
||||||
|
extern uint8_t usb_descriptor_configuration_full_speed[];
|
||||||
|
extern uint8_t usb_descriptor_configuration_high_speed[];
|
||||||
|
extern uint8_t usb_descriptor_string_languages[];
|
||||||
|
extern uint8_t usb_descriptor_string_manufacturer[];
|
||||||
|
extern uint8_t usb_descriptor_string_product[];
|
||||||
|
extern uint8_t usb_descriptor_string_serial_number[];
|
||||||
|
|
||||||
|
extern uint8_t* usb_descriptor_strings[];
|
303
firmware/usb_performance/usb_performance.c
Normal file
303
firmware/usb_performance/usb_performance.c
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <libopencm3/lpc43xx/cgu.h>
|
||||||
|
#include <libopencm3/lpc43xx/gpio.h>
|
||||||
|
#include <libopencm3/lpc43xx/nvic.h>
|
||||||
|
#include <libopencm3/lpc43xx/sgpio.h>
|
||||||
|
|
||||||
|
#include <hackrf_core.h>
|
||||||
|
#include <max5864.h>
|
||||||
|
#include <max2837.h>
|
||||||
|
#include <rffc5071.h>
|
||||||
|
#include <sgpio.h>
|
||||||
|
|
||||||
|
#include "usb.h"
|
||||||
|
#include "usb_type.h"
|
||||||
|
#include "usb_request.h"
|
||||||
|
#include "usb_descriptor.h"
|
||||||
|
#include "usb_standard_request.h"
|
||||||
|
|
||||||
|
uint8_t* const usb_bulk_buffer = (uint8_t*)0x20004000;
|
||||||
|
static volatile uint32_t usb_bulk_buffer_offset = 0;
|
||||||
|
static const uint32_t usb_bulk_buffer_mask = 32768 - 1;
|
||||||
|
|
||||||
|
usb_transfer_descriptor_t usb_td_bulk[2] ATTR_ALIGNED(64);
|
||||||
|
const uint_fast8_t usb_td_bulk_count = sizeof(usb_td_bulk) / sizeof(usb_td_bulk[0]);
|
||||||
|
|
||||||
|
static void usb_init_buffers_bulk() {
|
||||||
|
usb_td_bulk[0].next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
||||||
|
usb_td_bulk[0].total_bytes
|
||||||
|
= USB_TD_DTD_TOKEN_TOTAL_BYTES(16384)
|
||||||
|
| USB_TD_DTD_TOKEN_MULTO(0)
|
||||||
|
;
|
||||||
|
usb_td_bulk[0].buffer_pointer_page[0] = (uint32_t)&usb_bulk_buffer[0x0000];
|
||||||
|
usb_td_bulk[0].buffer_pointer_page[1] = (uint32_t)&usb_bulk_buffer[0x1000];
|
||||||
|
usb_td_bulk[0].buffer_pointer_page[2] = (uint32_t)&usb_bulk_buffer[0x2000];
|
||||||
|
usb_td_bulk[0].buffer_pointer_page[3] = (uint32_t)&usb_bulk_buffer[0x3000];
|
||||||
|
usb_td_bulk[0].buffer_pointer_page[4] = (uint32_t)&usb_bulk_buffer[0x4000];
|
||||||
|
|
||||||
|
usb_td_bulk[1].next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
||||||
|
usb_td_bulk[1].total_bytes
|
||||||
|
= USB_TD_DTD_TOKEN_TOTAL_BYTES(16384)
|
||||||
|
| USB_TD_DTD_TOKEN_MULTO(0)
|
||||||
|
;
|
||||||
|
usb_td_bulk[1].buffer_pointer_page[0] = (uint32_t)&usb_bulk_buffer[0x4000];
|
||||||
|
usb_td_bulk[1].buffer_pointer_page[1] = (uint32_t)&usb_bulk_buffer[0x5000];
|
||||||
|
usb_td_bulk[1].buffer_pointer_page[2] = (uint32_t)&usb_bulk_buffer[0x6000];
|
||||||
|
usb_td_bulk[1].buffer_pointer_page[3] = (uint32_t)&usb_bulk_buffer[0x7000];
|
||||||
|
usb_td_bulk[1].buffer_pointer_page[4] = (uint32_t)&usb_bulk_buffer[0x8000];
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_endpoint_schedule_no_int(
|
||||||
|
const usb_endpoint_t* const endpoint,
|
||||||
|
usb_transfer_descriptor_t* const td
|
||||||
|
) {
|
||||||
|
// Ensure that endpoint is ready to be primed.
|
||||||
|
// It may have been flushed due to an aborted transaction.
|
||||||
|
// TODO: This should be preceded by a flush?
|
||||||
|
while( usb_endpoint_is_ready(endpoint) );
|
||||||
|
|
||||||
|
// Configure a transfer.
|
||||||
|
td->total_bytes =
|
||||||
|
USB_TD_DTD_TOKEN_TOTAL_BYTES(16384)
|
||||||
|
/*| USB_TD_DTD_TOKEN_IOC*/
|
||||||
|
| USB_TD_DTD_TOKEN_MULTO(0)
|
||||||
|
| USB_TD_DTD_TOKEN_STATUS_ACTIVE
|
||||||
|
;
|
||||||
|
|
||||||
|
usb_endpoint_prime(endpoint, td);
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_configuration_t usb_configuration_high_speed = {
|
||||||
|
.number = 1,
|
||||||
|
.speed = USB_SPEED_HIGH,
|
||||||
|
.descriptor = usb_descriptor_configuration_high_speed,
|
||||||
|
};
|
||||||
|
|
||||||
|
usb_configuration_t usb_configuration_full_speed = {
|
||||||
|
.number = 1,
|
||||||
|
.speed = USB_SPEED_FULL,
|
||||||
|
.descriptor = usb_descriptor_configuration_full_speed,
|
||||||
|
};
|
||||||
|
|
||||||
|
usb_configuration_t* usb_configurations[] = {
|
||||||
|
&usb_configuration_high_speed,
|
||||||
|
&usb_configuration_full_speed,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
usb_device_t usb_device = {
|
||||||
|
.descriptor = usb_descriptor_device,
|
||||||
|
.configurations = &usb_configurations,
|
||||||
|
.configuration = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
usb_endpoint_t usb_endpoint_control_out;
|
||||||
|
usb_endpoint_t usb_endpoint_control_in;
|
||||||
|
|
||||||
|
usb_endpoint_t usb_endpoint_control_out = {
|
||||||
|
.address = 0x00,
|
||||||
|
.device = &usb_device,
|
||||||
|
.in = &usb_endpoint_control_in,
|
||||||
|
.out = &usb_endpoint_control_out,
|
||||||
|
.setup_complete = usb_setup_complete,
|
||||||
|
.transfer_complete = usb_control_out_complete,
|
||||||
|
};
|
||||||
|
|
||||||
|
usb_endpoint_t usb_endpoint_control_in = {
|
||||||
|
.address = 0x80,
|
||||||
|
.device = &usb_device,
|
||||||
|
.in = &usb_endpoint_control_in,
|
||||||
|
.out = &usb_endpoint_control_out,
|
||||||
|
.setup_complete = 0,
|
||||||
|
.transfer_complete = usb_control_in_complete,
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: Endpoint number for IN and OUT are different. I wish I had some
|
||||||
|
// evidence that having BULK IN and OUT on separate endpoint numbers was
|
||||||
|
// actually a good idea. Seems like everybody does it that way, but why?
|
||||||
|
|
||||||
|
usb_endpoint_t usb_endpoint_bulk_in = {
|
||||||
|
.address = 0x81,
|
||||||
|
.device = &usb_device,
|
||||||
|
.in = &usb_endpoint_bulk_in,
|
||||||
|
.out = 0,
|
||||||
|
.setup_complete = 0,
|
||||||
|
.transfer_complete = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
usb_endpoint_t usb_endpoint_bulk_out = {
|
||||||
|
.address = 0x02,
|
||||||
|
.device = &usb_device,
|
||||||
|
.in = 0,
|
||||||
|
.out = &usb_endpoint_bulk_out,
|
||||||
|
.setup_complete = 0,
|
||||||
|
.transfer_complete = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const usb_request_handlers_t usb_request_handlers = {
|
||||||
|
.standard = usb_standard_request,
|
||||||
|
.class = 0,
|
||||||
|
.vendor = 0,
|
||||||
|
.reserved = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Seems like this should live in usb_standard_request.c.
|
||||||
|
bool usb_set_configuration(
|
||||||
|
usb_device_t* const device,
|
||||||
|
const uint_fast8_t configuration_number
|
||||||
|
) {
|
||||||
|
const usb_configuration_t* new_configuration = 0;
|
||||||
|
if( configuration_number != 0 ) {
|
||||||
|
|
||||||
|
// Locate requested configuration.
|
||||||
|
if( device->configurations ) {
|
||||||
|
usb_configuration_t** configurations = *(device->configurations);
|
||||||
|
uint32_t i = 0;
|
||||||
|
const usb_speed_t usb_speed_current = usb_speed(device);
|
||||||
|
while( configurations[i] ) {
|
||||||
|
if( (configurations[i]->speed == usb_speed_current) &&
|
||||||
|
(configurations[i]->number == configuration_number) ) {
|
||||||
|
new_configuration = configurations[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requested configuration not found: request error.
|
||||||
|
if( new_configuration == 0 ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( new_configuration != device->configuration ) {
|
||||||
|
// Configuration changed.
|
||||||
|
device->configuration = new_configuration;
|
||||||
|
|
||||||
|
// TODO: This is lame. There should be a way to link stuff together so
|
||||||
|
// that changing the configuration will initialize the related
|
||||||
|
// endpoints. No hard-coding crap like this! Then, when there's no more
|
||||||
|
// hard-coding, this whole function can move into a shared/reusable
|
||||||
|
// library.
|
||||||
|
if( device->configuration && (device->configuration->number == 1) ) {
|
||||||
|
usb_endpoint_init(&usb_endpoint_bulk_in);
|
||||||
|
usb_endpoint_init(&usb_endpoint_bulk_out);
|
||||||
|
|
||||||
|
usb_init_buffers_bulk();
|
||||||
|
|
||||||
|
sgpio_configure_for_rx_deep();
|
||||||
|
|
||||||
|
nvic_set_priority(NVIC_M4_SGPIO_IRQ, 0);
|
||||||
|
nvic_enable_irq(NVIC_M4_SGPIO_IRQ);
|
||||||
|
SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A);
|
||||||
|
|
||||||
|
sgpio_cpld_stream_enable();
|
||||||
|
} else {
|
||||||
|
sgpio_cpld_stream_disable();
|
||||||
|
|
||||||
|
nvic_disable_irq(NVIC_M4_SGPIO_IRQ);
|
||||||
|
|
||||||
|
usb_endpoint_disable(&usb_endpoint_bulk_in);
|
||||||
|
usb_endpoint_disable(&usb_endpoint_bulk_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( device->configuration ) {
|
||||||
|
gpio_set(PORT_LED1_3, PIN_LED1);
|
||||||
|
} else {
|
||||||
|
gpio_clear(PORT_LED1_3, PIN_LED1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void sgpio_irqhandler() {
|
||||||
|
SGPIO_CLR_STATUS_1 = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
uint32_t* const p = (uint32_t*)&usb_bulk_buffer[usb_bulk_buffer_offset];
|
||||||
|
p[7] = SGPIO_REG_SS(SGPIO_SLICE_A);
|
||||||
|
p[6] = SGPIO_REG_SS(SGPIO_SLICE_I);
|
||||||
|
p[5] = SGPIO_REG_SS(SGPIO_SLICE_E);
|
||||||
|
p[4] = SGPIO_REG_SS(SGPIO_SLICE_J);
|
||||||
|
p[3] = SGPIO_REG_SS(SGPIO_SLICE_C);
|
||||||
|
p[2] = SGPIO_REG_SS(SGPIO_SLICE_K);
|
||||||
|
p[1] = SGPIO_REG_SS(SGPIO_SLICE_F);
|
||||||
|
p[0] = SGPIO_REG_SS(SGPIO_SLICE_L);
|
||||||
|
|
||||||
|
usb_bulk_buffer_offset = (usb_bulk_buffer_offset + 32) & usb_bulk_buffer_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
const uint32_t freq = 2441000000U;
|
||||||
|
uint8_t switchctrl = 0;
|
||||||
|
|
||||||
|
pin_setup();
|
||||||
|
enable_1v8_power();
|
||||||
|
cpu_clock_init();
|
||||||
|
|
||||||
|
CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK
|
||||||
|
| CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||||
|
|
||||||
|
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK
|
||||||
|
| CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||||
|
|
||||||
|
usb_peripheral_reset();
|
||||||
|
|
||||||
|
usb_device_init(0, &usb_device);
|
||||||
|
|
||||||
|
usb_endpoint_init(&usb_endpoint_control_out);
|
||||||
|
usb_endpoint_init(&usb_endpoint_control_in);
|
||||||
|
|
||||||
|
nvic_set_priority(NVIC_M4_USB0_IRQ, 255);
|
||||||
|
|
||||||
|
usb_run(&usb_device);
|
||||||
|
|
||||||
|
ssp1_init();
|
||||||
|
ssp1_set_mode_max2837();
|
||||||
|
max2837_setup();
|
||||||
|
|
||||||
|
rffc5071_setup();
|
||||||
|
#ifdef JAWBREAKER
|
||||||
|
switchctrl = (SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_HP);
|
||||||
|
#endif
|
||||||
|
rffc5071_rx(switchctrl);
|
||||||
|
rffc5071_set_frequency(500, 0); // 500 MHz, 0 Hz (Hz ignored)
|
||||||
|
|
||||||
|
max2837_set_frequency(freq);
|
||||||
|
max2837_start();
|
||||||
|
max2837_rx();
|
||||||
|
ssp1_set_mode_max5864();
|
||||||
|
max5864_xcvr();
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
while( usb_bulk_buffer_offset < 16384 );
|
||||||
|
usb_endpoint_schedule_no_int(&usb_endpoint_bulk_in, &usb_td_bulk[0]);
|
||||||
|
|
||||||
|
while( usb_bulk_buffer_offset >= 16384 );
|
||||||
|
usb_endpoint_schedule_no_int(&usb_endpoint_bulk_in, &usb_td_bulk[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
84
firmware/usb_performance/usb_request.c
Normal file
84
firmware/usb_performance/usb_request.c
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "usb_request.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
static void usb_request(
|
||||||
|
usb_endpoint_t* const endpoint,
|
||||||
|
const usb_transfer_stage_t stage
|
||||||
|
) {
|
||||||
|
usb_request_handler_fn handler = 0;
|
||||||
|
|
||||||
|
switch( endpoint->setup.request_type & USB_SETUP_REQUEST_TYPE_mask ) {
|
||||||
|
case USB_SETUP_REQUEST_TYPE_STANDARD:
|
||||||
|
handler = usb_request_handlers.standard;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_SETUP_REQUEST_TYPE_CLASS:
|
||||||
|
handler = usb_request_handlers.class;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_SETUP_REQUEST_TYPE_VENDOR:
|
||||||
|
handler = usb_request_handlers.vendor;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_SETUP_REQUEST_TYPE_RESERVED:
|
||||||
|
handler = usb_request_handlers.reserved;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( handler ) {
|
||||||
|
handler(endpoint, stage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_setup_complete(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
usb_request(endpoint, USB_TRANSFER_STAGE_SETUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_control_out_complete(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const bool device_to_host =
|
||||||
|
endpoint->setup.request_type >> USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_shift;
|
||||||
|
if( device_to_host ) {
|
||||||
|
usb_request(endpoint, USB_TRANSFER_STAGE_STATUS);
|
||||||
|
} else {
|
||||||
|
usb_request(endpoint, USB_TRANSFER_STAGE_DATA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_control_in_complete(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const bool device_to_host =
|
||||||
|
endpoint->setup.request_type >> USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_shift;
|
||||||
|
if( device_to_host ) {
|
||||||
|
usb_request(endpoint, USB_TRANSFER_STAGE_DATA);
|
||||||
|
} else {
|
||||||
|
usb_request(endpoint, USB_TRANSFER_STAGE_STATUS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
66
firmware/usb_performance/usb_request.h
Normal file
66
firmware/usb_performance/usb_request.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __USB_REQUEST_H__
|
||||||
|
#define __USB_REQUEST_H__
|
||||||
|
|
||||||
|
#include "usb_type.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USB_RESPONSE_NONE,
|
||||||
|
USB_RESPONSE_IN,
|
||||||
|
USB_RESPONSE_OUT,
|
||||||
|
USB_RESPONSE_STALL,
|
||||||
|
} usb_endpoint_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USB_TRANSFER_STAGE_SETUP,
|
||||||
|
USB_TRANSFER_STAGE_DATA,
|
||||||
|
USB_TRANSFER_STAGE_STATUS,
|
||||||
|
} usb_transfer_stage_t;
|
||||||
|
|
||||||
|
typedef void (*usb_request_handler_fn)(
|
||||||
|
usb_endpoint_t* const response,
|
||||||
|
const usb_transfer_stage_t stage
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
usb_request_handler_fn standard;
|
||||||
|
usb_request_handler_fn class;
|
||||||
|
usb_request_handler_fn vendor;
|
||||||
|
usb_request_handler_fn reserved;
|
||||||
|
} usb_request_handlers_t;
|
||||||
|
|
||||||
|
extern const usb_request_handlers_t usb_request_handlers;
|
||||||
|
|
||||||
|
void usb_setup_complete(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_control_in_complete(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
void usb_control_out_complete(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif//__USB_REQUEST_H__
|
278
firmware/usb_performance/usb_standard_request.c
Normal file
278
firmware/usb_performance/usb_standard_request.c
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "usb_standard_request.h"
|
||||||
|
|
||||||
|
#include "usb.h"
|
||||||
|
#include "usb_type.h"
|
||||||
|
#include "usb_descriptor.h"
|
||||||
|
|
||||||
|
const uint8_t* usb_endpoint_descriptor(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const usb_configuration_t* const configuration = endpoint->device->configuration;
|
||||||
|
if( configuration ) {
|
||||||
|
const uint8_t* descriptor = configuration->descriptor;
|
||||||
|
while( descriptor[0] != 0 ) {
|
||||||
|
if( descriptor[1] == USB_DESCRIPTOR_TYPE_ENDPOINT ) {
|
||||||
|
if( descriptor[2] == endpoint->address ) {
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
descriptor += descriptor[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint_fast16_t usb_endpoint_descriptor_max_packet_size(
|
||||||
|
const uint8_t* const endpoint_descriptor
|
||||||
|
) {
|
||||||
|
return (endpoint_descriptor[5] << 8) | endpoint_descriptor[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_transfer_type_t usb_endpoint_descriptor_transfer_type(
|
||||||
|
const uint8_t* const endpoint_descriptor
|
||||||
|
) {
|
||||||
|
return (endpoint_descriptor[3] & 0x3);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern bool usb_set_configuration(
|
||||||
|
usb_device_t* const device,
|
||||||
|
const uint_fast8_t configuration_number
|
||||||
|
);
|
||||||
|
|
||||||
|
static void usb_send_descriptor(
|
||||||
|
usb_endpoint_t* const endpoint,
|
||||||
|
uint8_t* const descriptor_data
|
||||||
|
) {
|
||||||
|
const uint32_t setup_length = (endpoint->setup.length_h << 8) | endpoint->setup.length_l;
|
||||||
|
uint32_t descriptor_length = descriptor_data[0];
|
||||||
|
if( descriptor_data[1] == USB_DESCRIPTOR_TYPE_CONFIGURATION ) {
|
||||||
|
descriptor_length = (descriptor_data[3] << 8) | descriptor_data[2];
|
||||||
|
}
|
||||||
|
usb_endpoint_schedule(
|
||||||
|
endpoint->in,
|
||||||
|
descriptor_data,
|
||||||
|
(setup_length > descriptor_length) ? descriptor_length : setup_length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_send_descriptor_string(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
uint_fast8_t index = endpoint->setup.value_l;
|
||||||
|
for( uint_fast8_t i=0; usb_descriptor_strings[i] != 0; i++ ) {
|
||||||
|
if( i == index ) {
|
||||||
|
usb_send_descriptor(endpoint, usb_descriptor_strings[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_endpoint_stall(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_standard_request_get_descriptor_setup(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
switch( endpoint->setup.value_h ) {
|
||||||
|
case USB_DESCRIPTOR_TYPE_DEVICE:
|
||||||
|
usb_send_descriptor(endpoint, usb_descriptor_device);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_DESCRIPTOR_TYPE_CONFIGURATION:
|
||||||
|
// TODO: Duplicated code. Refactor.
|
||||||
|
if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) {
|
||||||
|
usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed);
|
||||||
|
} else {
|
||||||
|
usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
|
||||||
|
usb_send_descriptor(endpoint, usb_descriptor_device_qualifier);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION:
|
||||||
|
// TODO: Duplicated code. Refactor.
|
||||||
|
if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) {
|
||||||
|
usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed);
|
||||||
|
} else {
|
||||||
|
usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_DESCRIPTOR_TYPE_STRING:
|
||||||
|
usb_send_descriptor_string(endpoint);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_DESCRIPTOR_TYPE_INTERFACE:
|
||||||
|
case USB_DESCRIPTOR_TYPE_ENDPOINT:
|
||||||
|
default:
|
||||||
|
usb_endpoint_stall(endpoint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_standard_request_get_descriptor(
|
||||||
|
usb_endpoint_t* const endpoint,
|
||||||
|
const usb_transfer_stage_t stage
|
||||||
|
) {
|
||||||
|
switch( stage ) {
|
||||||
|
case USB_TRANSFER_STAGE_SETUP:
|
||||||
|
usb_standard_request_get_descriptor_setup(endpoint);
|
||||||
|
usb_endpoint_schedule_ack(endpoint->out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_TRANSFER_STAGE_DATA:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_TRANSFER_STAGE_STATUS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
static void usb_standard_request_set_address(
|
||||||
|
usb_endpoint_t* const endpoint,
|
||||||
|
const usb_transfer_stage_t stage
|
||||||
|
) {
|
||||||
|
switch( stage ) {
|
||||||
|
case USB_TRANSFER_STAGE_SETUP:
|
||||||
|
usb_set_address_deferred(endpoint->device, endpoint->setup.value_l);
|
||||||
|
usb_endpoint_schedule_ack(endpoint->in);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_TRANSFER_STAGE_DATA:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_TRANSFER_STAGE_STATUS:
|
||||||
|
/* NOTE: Not necessary to set address here, as DEVICEADR.USBADRA bit
|
||||||
|
* will cause controller to automatically perform set address
|
||||||
|
* operation on IN ACK.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
static void usb_standard_request_set_configuration_setup(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
const uint8_t usb_configuration = endpoint->setup.value_l;
|
||||||
|
if( usb_set_configuration(endpoint->device, usb_configuration) ) {
|
||||||
|
if( usb_configuration == 0 ) {
|
||||||
|
// TODO: Should this be done immediately?
|
||||||
|
usb_set_address_immediate(endpoint->device, 0);
|
||||||
|
}
|
||||||
|
usb_endpoint_schedule_ack(endpoint->in);
|
||||||
|
} else {
|
||||||
|
usb_endpoint_stall(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_standard_request_set_configuration(
|
||||||
|
usb_endpoint_t* const endpoint,
|
||||||
|
const usb_transfer_stage_t stage
|
||||||
|
) {
|
||||||
|
switch( stage ) {
|
||||||
|
case USB_TRANSFER_STAGE_SETUP:
|
||||||
|
usb_standard_request_set_configuration_setup(endpoint);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_TRANSFER_STAGE_DATA:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_TRANSFER_STAGE_STATUS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
static void usb_standard_request_get_configuration_setup(
|
||||||
|
usb_endpoint_t* const endpoint
|
||||||
|
) {
|
||||||
|
if( (endpoint->setup.length_h == 0) && (endpoint->setup.length_l == 1) ) {
|
||||||
|
endpoint->buffer[0] = 0;
|
||||||
|
if( endpoint->device->configuration ) {
|
||||||
|
endpoint->buffer[0] = endpoint->device->configuration->number;
|
||||||
|
}
|
||||||
|
usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1);
|
||||||
|
} else {
|
||||||
|
usb_endpoint_stall(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_standard_request_get_configuration(
|
||||||
|
usb_endpoint_t* const endpoint,
|
||||||
|
const usb_transfer_stage_t stage
|
||||||
|
) {
|
||||||
|
switch( stage ) {
|
||||||
|
case USB_TRANSFER_STAGE_SETUP:
|
||||||
|
usb_standard_request_get_configuration_setup(endpoint);
|
||||||
|
usb_endpoint_schedule_ack(endpoint->out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_TRANSFER_STAGE_DATA:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_TRANSFER_STAGE_STATUS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
void usb_standard_request(
|
||||||
|
usb_endpoint_t* const endpoint,
|
||||||
|
const usb_transfer_stage_t stage
|
||||||
|
) {
|
||||||
|
switch( endpoint->setup.request ) {
|
||||||
|
case USB_STANDARD_REQUEST_GET_DESCRIPTOR:
|
||||||
|
usb_standard_request_get_descriptor(endpoint, stage);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_STANDARD_REQUEST_SET_ADDRESS:
|
||||||
|
usb_standard_request_set_address(endpoint, stage);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_STANDARD_REQUEST_SET_CONFIGURATION:
|
||||||
|
usb_standard_request_set_configuration(endpoint, stage);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_STANDARD_REQUEST_GET_CONFIGURATION:
|
||||||
|
usb_standard_request_get_configuration(endpoint, stage);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
45
firmware/usb_performance/usb_standard_request.h
Normal file
45
firmware/usb_performance/usb_standard_request.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __USB_STANDARD_REQUEST_H__
|
||||||
|
#define __USB_STANDARD_REQUEST_H__
|
||||||
|
|
||||||
|
#include "usb_type.h"
|
||||||
|
#include "usb_request.h"
|
||||||
|
|
||||||
|
void usb_standard_request(
|
||||||
|
usb_endpoint_t* const endpoint,
|
||||||
|
const usb_transfer_stage_t stage
|
||||||
|
);
|
||||||
|
|
||||||
|
const uint8_t* usb_endpoint_descriptor(
|
||||||
|
const usb_endpoint_t* const endpoint
|
||||||
|
);
|
||||||
|
|
||||||
|
uint_fast16_t usb_endpoint_descriptor_max_packet_size(
|
||||||
|
const uint8_t* const endpoint_descriptor
|
||||||
|
);
|
||||||
|
|
||||||
|
usb_transfer_type_t usb_endpoint_descriptor_transfer_type(
|
||||||
|
const uint8_t* const endpoint_descriptor
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif//__USB_STANDARD_REQUEST_H__
|
122
firmware/usb_performance/usb_type.h
Normal file
122
firmware/usb_performance/usb_type.h
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __USB_TYPE_H__
|
||||||
|
#define __USB_TYPE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t request_type;
|
||||||
|
uint8_t request;
|
||||||
|
uint8_t value_l;
|
||||||
|
uint8_t value_h;
|
||||||
|
uint8_t index_l;
|
||||||
|
uint8_t index_h;
|
||||||
|
uint8_t length_l;
|
||||||
|
uint8_t length_h;
|
||||||
|
} usb_setup_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USB_STANDARD_REQUEST_GET_STATUS = 0,
|
||||||
|
USB_STANDARD_REQUEST_CLEAR_FEATURE = 1,
|
||||||
|
USB_STANDARD_REQUEST_SET_FEATURE = 3,
|
||||||
|
USB_STANDARD_REQUEST_SET_ADDRESS = 5,
|
||||||
|
USB_STANDARD_REQUEST_GET_DESCRIPTOR = 6,
|
||||||
|
USB_STANDARD_REQUEST_SET_DESCRIPTOR = 7,
|
||||||
|
USB_STANDARD_REQUEST_GET_CONFIGURATION = 8,
|
||||||
|
USB_STANDARD_REQUEST_SET_CONFIGURATION = 9,
|
||||||
|
USB_STANDARD_REQUEST_GET_INTERFACE = 10,
|
||||||
|
USB_STANDARD_REQUEST_SET_INTERFACE = 11,
|
||||||
|
USB_STANDARD_REQUEST_SYNCH_FRAME = 12,
|
||||||
|
} usb_standard_request_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USB_SETUP_REQUEST_TYPE_shift = 5,
|
||||||
|
USB_SETUP_REQUEST_TYPE_mask = 3 << USB_SETUP_REQUEST_TYPE_shift,
|
||||||
|
|
||||||
|
USB_SETUP_REQUEST_TYPE_STANDARD = 0 << USB_SETUP_REQUEST_TYPE_shift,
|
||||||
|
USB_SETUP_REQUEST_TYPE_CLASS = 1 << USB_SETUP_REQUEST_TYPE_shift,
|
||||||
|
USB_SETUP_REQUEST_TYPE_VENDOR = 2 << USB_SETUP_REQUEST_TYPE_shift,
|
||||||
|
USB_SETUP_REQUEST_TYPE_RESERVED = 3 << USB_SETUP_REQUEST_TYPE_shift,
|
||||||
|
|
||||||
|
USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_shift = 7,
|
||||||
|
USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_mask = 1 << USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_shift,
|
||||||
|
USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_HOST_TO_DEVICE = 0 << USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_shift,
|
||||||
|
USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_DEVICE_TO_HOST = 1 << USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_shift,
|
||||||
|
} usb_setup_request_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USB_TRANSFER_DIRECTION_OUT = 0,
|
||||||
|
USB_TRANSFER_DIRECTION_IN = 1,
|
||||||
|
} usb_transfer_direction_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USB_DESCRIPTOR_TYPE_DEVICE = 1,
|
||||||
|
USB_DESCRIPTOR_TYPE_CONFIGURATION = 2,
|
||||||
|
USB_DESCRIPTOR_TYPE_STRING = 3,
|
||||||
|
USB_DESCRIPTOR_TYPE_INTERFACE = 4,
|
||||||
|
USB_DESCRIPTOR_TYPE_ENDPOINT = 5,
|
||||||
|
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER = 6,
|
||||||
|
USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION = 7,
|
||||||
|
USB_DESCRIPTOR_TYPE_INTERFACE_POWER = 8,
|
||||||
|
} usb_descriptor_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USB_TRANSFER_TYPE_CONTROL = 0,
|
||||||
|
USB_TRANSFER_TYPE_ISOCHRONOUS = 1,
|
||||||
|
USB_TRANSFER_TYPE_BULK = 2,
|
||||||
|
USB_TRANSFER_TYPE_INTERRUPT = 3,
|
||||||
|
} usb_transfer_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USB_SPEED_LOW = 0,
|
||||||
|
USB_SPEED_FULL = 1,
|
||||||
|
USB_SPEED_HIGH = 2,
|
||||||
|
USB_SPEED_SUPER = 3,
|
||||||
|
} usb_speed_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const uint8_t* const descriptor;
|
||||||
|
const uint32_t number;
|
||||||
|
const usb_speed_t speed;
|
||||||
|
} usb_configuration_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const uint8_t* const descriptor;
|
||||||
|
usb_configuration_t* (*configurations)[];
|
||||||
|
const usb_configuration_t* configuration;
|
||||||
|
} usb_device_t;
|
||||||
|
|
||||||
|
typedef struct usb_endpoint_t usb_endpoint_t;
|
||||||
|
struct usb_endpoint_t {
|
||||||
|
usb_setup_t setup;
|
||||||
|
uint8_t buffer[8]; // Buffer for use during IN stage.
|
||||||
|
const uint_fast8_t address;
|
||||||
|
usb_device_t* const device;
|
||||||
|
usb_endpoint_t* const in;
|
||||||
|
usb_endpoint_t* const out;
|
||||||
|
void (*setup_complete)(usb_endpoint_t* const endpoint);
|
||||||
|
void (*transfer_complete)(usb_endpoint_t* const endpoint);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif//__USB_TYPE_H__
|
77
host/usb_test/Makefile
Normal file
77
host/usb_test/Makefile
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#
|
||||||
|
# Copyright 2010 Michael Ossmann <mike@ossmann.com>
|
||||||
|
# Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
#
|
||||||
|
# This file is part of HackRF.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# This program 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 General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; see the file COPYING. If not, write to
|
||||||
|
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
# Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
# derived primarily from Makefiles in Project Ubertooth
|
||||||
|
|
||||||
|
CC ?= gcc
|
||||||
|
AR ?= ar
|
||||||
|
INSTALL ?= /usr/bin/install
|
||||||
|
LDCONFIG ?= /sbin/ldconfig
|
||||||
|
|
||||||
|
OPTFLAGS = -O2
|
||||||
|
ANGRYFLAGS = -Wall #-Wextra -pedantic
|
||||||
|
CFLAGS += $(OPTFLAGS) $(ANGRYFLAGS)
|
||||||
|
|
||||||
|
LIB_DIR ?= /usr/lib
|
||||||
|
INCLUDE_DIR ?= /usr/include
|
||||||
|
INSTALL_DIR ?= /usr/bin
|
||||||
|
|
||||||
|
OS = $(shell uname)
|
||||||
|
ifeq ($(OS), FreeBSD)
|
||||||
|
LIBUSB = usb
|
||||||
|
CFLAGS += -DFREEBSD
|
||||||
|
else
|
||||||
|
LIBUSB = usb-1.0
|
||||||
|
endif
|
||||||
|
|
||||||
|
LDFLAGS += -l$(LIBUSB)
|
||||||
|
|
||||||
|
TOOLS = usb_test
|
||||||
|
|
||||||
|
ifeq ($(OS), Darwin)
|
||||||
|
CFLAGS += -I/opt/local/include/
|
||||||
|
LDFLAGS += -L/opt/local/lib/ -rpath,/opt/local/lib
|
||||||
|
else
|
||||||
|
#
|
||||||
|
endif
|
||||||
|
|
||||||
|
TOOLS_SOURCE = $(TOOLS:%=%.c)
|
||||||
|
|
||||||
|
all: $(TOOLS)
|
||||||
|
|
||||||
|
$(TOOLS): $(TOOLS_SOURCE)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $@.c $(LDFLAGS)
|
||||||
|
|
||||||
|
install: $(TOOLS)
|
||||||
|
$(INSTALL) -m 0755 $(TOOLS) $(INSTALL_DIR)
|
||||||
|
|
||||||
|
cygwin-install: $(LIB_FILE) $(STATIC_LIB_FILE)
|
||||||
|
$(INSTALL) -m 0755 $(TOOLS) $(INSTALL_DIR)
|
||||||
|
|
||||||
|
osx-install: $(LIB_FILE) $(TOOLS)
|
||||||
|
$(INSTALL) -m 0755 $(TOOLS) $(INSTALL_DIR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TOOLS)
|
||||||
|
|
||||||
|
.PHONY: all clean install cygwin-install osx-install
|
172
host/usb_test/usb_test.c
Normal file
172
host/usb_test/usb_test.c
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||||
|
*
|
||||||
|
* This file is part of HackRF.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libusb-1.0/libusb.h>
|
||||||
|
|
||||||
|
static float
|
||||||
|
TimevalDiff(const struct timeval *a, const struct timeval *b)
|
||||||
|
{
|
||||||
|
return (a->tv_sec - b->tv_sec) + 1e-6f * (a->tv_usec - b->tv_usec);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = -1;
|
||||||
|
struct timeval time_start;
|
||||||
|
volatile uint32_t byte_count = 0;
|
||||||
|
|
||||||
|
void write_callback(struct libusb_transfer* transfer) {
|
||||||
|
if( transfer->status == LIBUSB_TRANSFER_COMPLETED ) {
|
||||||
|
byte_count += transfer->actual_length;
|
||||||
|
write(fd, transfer->buffer, transfer->actual_length);
|
||||||
|
libusb_submit_transfer(transfer);
|
||||||
|
} else {
|
||||||
|
printf("transfer status was not 'completed'\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if( argc != 2 ) {
|
||||||
|
printf("Usage: usb_test <file to capture to>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t buffer_size = 16384;
|
||||||
|
|
||||||
|
fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||||
|
if( fd == -1 ) {
|
||||||
|
printf("Failed to open file for write\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_context* context = NULL;
|
||||||
|
int result = libusb_init(NULL);
|
||||||
|
if( result != 0 ) {
|
||||||
|
printf("libusb_init() failed: %d\n", result);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_device_handle* device = libusb_open_device_with_vid_pid(context, 0x1d50, 0x604b);
|
||||||
|
if( device == NULL ) {
|
||||||
|
printf("libusb_open_device_with_vid_pid() failed\n");
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//int speed = libusb_get_device_speed(device);
|
||||||
|
//printf("device speed: %d\n", speed);
|
||||||
|
|
||||||
|
result = libusb_set_configuration(device, 1);
|
||||||
|
if( result != 0 ) {
|
||||||
|
printf("libusb_set_configuration() failed: %d\n", result);
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = libusb_claim_interface(device, 0);
|
||||||
|
if( result != 0 ) {
|
||||||
|
printf("libusb_claim_interface() failed: %d\n", result);
|
||||||
|
return -7;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char endpoint_address = 0x81;
|
||||||
|
//unsigned char endpoint_address = 0x02;
|
||||||
|
|
||||||
|
const uint32_t transfer_count = 1024;
|
||||||
|
struct libusb_transfer* transfers[transfer_count];
|
||||||
|
for(uint32_t transfer_index=0; transfer_index<transfer_count; transfer_index++) {
|
||||||
|
transfers[transfer_index] = libusb_alloc_transfer(0);
|
||||||
|
if( transfers[transfer_index] == 0 ) {
|
||||||
|
printf("libusb_alloc_transfer() failed\n");
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_fill_bulk_transfer(
|
||||||
|
transfers[transfer_index],
|
||||||
|
device,
|
||||||
|
endpoint_address,
|
||||||
|
(unsigned char*)malloc(buffer_size),
|
||||||
|
buffer_size,
|
||||||
|
&write_callback,
|
||||||
|
NULL,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if( transfers[transfer_index]->buffer == 0 ) {
|
||||||
|
printf("malloc() failed\n");
|
||||||
|
return -7;
|
||||||
|
}
|
||||||
|
|
||||||
|
int error = libusb_submit_transfer(transfers[transfer_index]);
|
||||||
|
if( error != 0 ) {
|
||||||
|
printf("libusb_submit_transfer() failed: %d\n", error);
|
||||||
|
return -8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct timeval timeout = { 0, 500000 };
|
||||||
|
struct timeval time_now;
|
||||||
|
|
||||||
|
const double progress_interval = 1.0;
|
||||||
|
gettimeofday(&time_start, NULL);
|
||||||
|
|
||||||
|
uint32_t call_count = 0;
|
||||||
|
do {
|
||||||
|
int error = libusb_handle_events_timeout(context, &timeout);
|
||||||
|
if( error != 0 ) {
|
||||||
|
printf("libusb_handle_events_timeout() failed: %d\n", error);
|
||||||
|
return -10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (call_count & 0xFF) == 0 ) {
|
||||||
|
gettimeofday(&time_now, NULL);
|
||||||
|
const float time_difference = TimevalDiff(&time_now, &time_start);
|
||||||
|
if( time_difference >= progress_interval ) {
|
||||||
|
const float rate = (float)byte_count / time_difference;
|
||||||
|
printf("%.1f/%.3f = %.1f MiB/second\n",
|
||||||
|
byte_count / 1e6f,
|
||||||
|
time_difference,
|
||||||
|
rate / 1e6f
|
||||||
|
);
|
||||||
|
time_start = time_now;
|
||||||
|
byte_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
call_count += 1;
|
||||||
|
} while(1);
|
||||||
|
|
||||||
|
result = libusb_release_interface(device, 0);
|
||||||
|
if( result != 0 ) {
|
||||||
|
printf("libusb_release_interface() failed: %d\n", result);
|
||||||
|
return -2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_close(device);
|
||||||
|
|
||||||
|
libusb_exit(context);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user