diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 00000000..f50cdb58 --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,58 @@ +# Hey Emacs, this is a -*- makefile -*- +# +# 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. +# + +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 diff --git a/firmware/blinky/Makefile b/firmware/blinky/Makefile index 96e5a9ba..468916f3 100644 --- a/firmware/blinky/Makefile +++ b/firmware/blinky/Makefile @@ -1,7 +1,30 @@ # Hey Emacs, this is a -*- makefile -*- +# +# Copyright 2012 Michael Ossmann +# 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. +# BINARY = blinky -SRC = $(BINARY).c +SRC = $(BINARY).c \ + ../common/hackrf_core.c \ + ../common/si5351c.c include ../common/Makefile_inc.mk diff --git a/firmware/blinky/blinky.c b/firmware/blinky/blinky.c index 8842ff9d..2c0c0011 100644 --- a/firmware/blinky/blinky.c +++ b/firmware/blinky/blinky.c @@ -24,43 +24,12 @@ #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; int main(void) { int i; - gpio_setup(); + pin_setup(); /* Set 1V8 */ gpio_set(PORT_EN1V8, PIN_EN1V8); diff --git a/firmware/blinky_rom_to_ram/Makefile b/firmware/blinky_rom_to_ram/Makefile index 936e0348..b93e84e6 100644 --- a/firmware/blinky_rom_to_ram/Makefile +++ b/firmware/blinky_rom_to_ram/Makefile @@ -1,8 +1,31 @@ # Hey Emacs, this is a -*- makefile -*- +# +# Copyright 2012 Michael Ossmann +# 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. +# BINARY = blinky -SRC = $(BINARY).c +SRC = $(BINARY).c \ + ../common/hackrf_core.c \ + ../common/si5351c.c LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld include ../common/Makefile_inc.mk diff --git a/firmware/blinky_rom_to_ram/blinky.c b/firmware/blinky_rom_to_ram/blinky.c index 8842ff9d..2c0c0011 100644 --- a/firmware/blinky_rom_to_ram/blinky.c +++ b/firmware/blinky_rom_to_ram/blinky.c @@ -24,43 +24,12 @@ #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; int main(void) { int i; - gpio_setup(); + pin_setup(); /* Set 1V8 */ gpio_set(PORT_EN1V8, PIN_EN1V8); diff --git a/firmware/common/LPC4330_M4.ld b/firmware/common/LPC4330_M4.ld index d73b4d47..694fd265 100644 --- a/firmware/common/LPC4330_M4.ld +++ b/firmware/common/LPC4330_M4.ld @@ -1,5 +1,6 @@ /* * Copyright 2012 Michael Ossmann + * Copyright 2012 Jared Boone * * 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 (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 */ + 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. */ diff --git a/firmware/common/LPC4330_M4_ROM_to_RAM.ld b/firmware/common/LPC4330_M4_ROM_to_RAM.ld index e3852933..f6b1d008 100644 --- a/firmware/common/LPC4330_M4_ROM_to_RAM.ld +++ b/firmware/common/LPC4330_M4_ROM_to_RAM.ld @@ -1,6 +1,7 @@ /* * Copyright 2012 Michael Ossmann * Copyright (C) 2012 Benjamin Vernoux + * Copyright 2012 Jared Boone * * This file is part of HackRF * @@ -28,9 +29,14 @@ MEMORY rom_flash (rx) : ORIGIN = 0x80000000, LENGTH = 1M /* rom is really the shadow region that points to SPI flash or elsewhere */ rom (rx) : ORIGIN = 0x00000000, LENGTH = 1M - ram (rwx) : ORIGIN = 0x10000000, LENGTH = 128K - /* there are some additional RAM regions for data */ - ram_data (rw) : ORIGIN = 0x10080000, LENGTH = 72K + 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. */ diff --git a/firmware/common/LPC4330_M4_ram_only.ld b/firmware/common/LPC4330_M4_ram_only.ld new file mode 100644 index 00000000..4149fbd7 --- /dev/null +++ b/firmware/common/LPC4330_M4_ram_only.ld @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Michael Ossmann + * 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. + */ + +/* 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 diff --git a/firmware/common/Makefile_inc.mk b/firmware/common/Makefile_inc.mk index 384fd9f1..8ea2f6be 100644 --- a/firmware/common/Makefile_inc.mk +++ b/firmware/common/Makefile_inc.mk @@ -4,6 +4,7 @@ # Copyright 2010 Piotr Esden-Tempski # Copyright 2012 Michael Ossmann # Copyright 2012 Benjamin Vernoux +# Copyright 2012 Jared Boone # # This file is part of HackRF. # @@ -45,12 +46,13 @@ OBJDUMP = $(PREFIX)-objdump GDB = $(PREFIX)-gdb 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 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \ $(HACKRF_OPTS) #LDSCRIPT ?= $(BINARY).ld LDFLAGS += -L$(TOOLCHAIN_DIR)/lib/armv7e-m/fpu \ + -L../common \ -L$(LIBOPENCM3)/lib -L$(LIBOPENCM3)/lib/lpc43xx \ -T$(LDSCRIPT) -nostartfiles \ -Wl,--gc-sections -Xlinker -Map=$(BINARY).map diff --git a/firmware/common/bitband.c b/firmware/common/bitband.c new file mode 100644 index 00000000..8f4e618b --- /dev/null +++ b/firmware/common/bitband.c @@ -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. + */ + +#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; +} diff --git a/firmware/common/bitband.h b/firmware/common/bitband.h new file mode 100644 index 00000000..03aef8d2 --- /dev/null +++ b/firmware/common/bitband.h @@ -0,0 +1,32 @@ +/* + * 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 __BITBAND_H__ +#define __BITBAND_H__ + +#include + +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__ diff --git a/firmware/common/fault_handler.c b/firmware/common/fault_handler.c new file mode 100644 index 00000000..7dce1f3e --- /dev/null +++ b/firmware/common/fault_handler.c @@ -0,0 +1,69 @@ +/* + * 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 + +#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); +} diff --git a/firmware/common/fault_handler.h b/firmware/common/fault_handler.h new file mode 100644 index 00000000..f52e760e --- /dev/null +++ b/firmware/common/fault_handler.h @@ -0,0 +1,73 @@ +/* + * 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 __FAULT_HANDLER__ +#define __FAULT_HANDLER__ + +#include + +#include + +// 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__ diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 88accc11..3bca88df 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -1,6 +1,6 @@ /* - * Copyright 2012 Michael Ossmann - * Copyright 2012 Jared Boone + * Copyright 2012 Michael Ossmann + * Copyright 2012 Jared Boone * * This file is part of HackRF. * @@ -53,9 +53,9 @@ void cpu_clock_init(void) /* * Jellybean/Lemondrop clocks: * CLK0 -> MAX2837 - * CLK1 -> MAX5864/CPLD - * CLK2 -> CPLD - * CLK3 -> CPLD + * CLK1 -> MAX5864/CPLD.GCLK0 + * CLK2 -> CPLD.GCLK1 + * CLK3 -> CPLD.GCLK2 * CLK4 -> LPC4330 * CLK5 -> RFFC5072 * CLK6 -> extra @@ -142,51 +142,46 @@ void cpu_clock_init(void) CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE; /* 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 */ - CGU_BASE_APB1_CLK = (CGU_BASE_CLK_AUTOBLOCK - | (CGU_SRC_XTAL << CGU_BASE_CLK_SEL_SHIFT)); + CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK + | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL); /* use XTAL_OSC as clock source for PLL1 */ - CGU_PLL1_CTRL = (CGU_PLL1_CTRL_AUTOBLOCK - | (CGU_SRC_XTAL << CGU_PLL1_CTRL_CLK_SEL_SHIFT)); - - /* configure PLL1 to produce 204 MHz clock from 12 MHz XTAL_OSC */ - /* not sure why, but it doesn't work without the following line */ - CGU_PLL1_CTRL &= ~(CGU_PLL1_CTRL_BYPASS - | 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)); + /* Start PLL1 at 12MHz * 17 / 2 = 102MHz. */ + CGU_PLL1_CTRL = CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL) + | CGU_PLL1_CTRL_PSEL(1) + | CGU_PLL1_CTRL_NSEL(0) + | CGU_PLL1_CTRL_MSEL(16) + | CGU_PLL1_CTRL_PD; /* power on PLL1 and wait until stable */ CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_PD; while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK)); /* 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 */ - CGU_PLL0USB_CTRL = (CGU_PLL0USB_CTRL_PD + CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD | 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); /* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */ - CGU_PLL0USB_MDIV = ((0x07FFA << CGU_PLL0USB_MDIV_MDEC_SHIFT) - | (0x0B << CGU_PLL0USB_SELP_MDEC_SHIFT) - | (0x10 << CGU_PLL0USB_SELI_MDEC_SHIFT) - | (0x0 << CGU_PLL0USB_SELR_MDEC_SHIFT)); - CGU_PLL0USB_NP_DIV = (98 << CGU_PLL0USB_NP_DIV_PDEC_SHIFT) - | (514 << CGU_PLL0USB_NP_DIV_NDEC_SHIFT); + /* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */ + CGU_PLL0USB_MDIV = 0x06167FFA; + CGU_PLL0USB_NP_DIV = 0x00302062; CGU_PLL0USB_CTRL |= (CGU_PLL0USB_CTRL_PD | CGU_PLL0USB_CTRL_DIRECTI | CGU_PLL0USB_CTRL_DIRECTO @@ -197,8 +192,8 @@ void cpu_clock_init(void) while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK)); /* use PLL0USB as clock source for USB0 */ - CGU_BASE_USB0_CLK = (CGU_BASE_CLK_AUTOBLOCK - | (CGU_SRC_PLL0USB << CGU_BASE_CLK_SEL_SHIFT)); + CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK + | CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB); } void ssp1_init(void) @@ -254,3 +249,54 @@ void ssp1_set_mode_max5864(void) SSP_MASTER, 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); +} diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index f4155f08..37722b1c 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -1,7 +1,7 @@ /* * Copyright 2012 Michael Ossmann * Copyright 2012 Benjamin Vernoux - * Copyright (C) 2012 Jared Boone + * Copyright 2012 Jared Boone * * This file is part of HackRF. * @@ -29,6 +29,8 @@ extern "C" { #endif +#include + /* hardware identification number */ #define BOARD_ID_JELLYBEAN 0 #define BOARD_ID_JAWBREAKER 1 @@ -198,11 +200,17 @@ extern "C" /* TODO add other Pins */ +void delay(uint32_t duration); + void cpu_clock_init(void); void ssp1_init(void); void ssp1_set_mode_max2837(void); void ssp1_set_mode_max5864(void); +void pin_setup(void); + +void enable_1v8_power(void); + #ifdef __cplusplus } #endif diff --git a/firmware/common/max5864.c b/firmware/common/max5864.c index 711bdbbd..a0f5dcff 100644 --- a/firmware/common/max5864.c +++ b/firmware/common/max5864.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Jared Boone + * Copyright 2012 Jared Boone * * This file is part of HackRF. * diff --git a/firmware/common/max5864.h b/firmware/common/max5864.h index 0af59415..72519645 100644 --- a/firmware/common/max5864.h +++ b/firmware/common/max5864.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Jared Boone + * Copyright 2012 Jared Boone * * This file is part of HackRF. * diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c index e3cc0109..590bbfb1 100644 --- a/firmware/common/rffc5071.c +++ b/firmware/common/rffc5071.c @@ -379,6 +379,8 @@ void rffc5071_tx(uint8_t gpo) { gpo |= SWITCHCTRL_NO_TX_AMP_PWR; gpo |= (SWITCHCTRL_TX | SWITCHCTRL_NO_RX_AMP_PWR); rffc5071_set_gpo(gpo); +#else + (void)gpo; #endif rffc5071_regs_commit(); @@ -403,6 +405,8 @@ void rffc5071_rx(uint8_t gpo) { gpo |= SWITCHCTRL_NO_RX_AMP_PWR; gpo |= SWITCHCTRL_NO_TX_AMP_PWR; rffc5071_set_gpo(gpo); +#else + (void)gpo; #endif rffc5071_regs_commit(); diff --git a/firmware/common/sgpio.c b/firmware/common/sgpio.c new file mode 100644 index 00000000..2db69608 --- /dev/null +++ b/firmware/common/sgpio.c @@ -0,0 +1,301 @@ +/* + * 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 +#include + +#include + +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; +} \ No newline at end of file diff --git a/firmware/common/sgpio.h b/firmware/common/sgpio.h new file mode 100644 index 00000000..8b8f471c --- /dev/null +++ b/firmware/common/sgpio.h @@ -0,0 +1,34 @@ +/* + * 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 __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__ diff --git a/firmware/common/si5351c.c b/firmware/common/si5351c.c index fa506150..eff4b498 100644 --- a/firmware/common/si5351c.c +++ b/firmware/common/si5351c.c @@ -1,6 +1,6 @@ /* - * Copyright 2012 Michael Ossmann - * Copyright 2012 Jared Boone + * Copyright 2012 Michael Ossmann + * Copyright 2012 Jared Boone * * This file is part of HackRF. * diff --git a/firmware/common/si5351c.h b/firmware/common/si5351c.h index 729619af..740da2f4 100644 --- a/firmware/common/si5351c.h +++ b/firmware/common/si5351c.h @@ -1,6 +1,6 @@ /* - * Copyright 2012 Michael Ossmann - * Copyright 2012 Jared Boone + * Copyright 2012 Michael Ossmann + * Copyright 2012 Jared Boone * * This file is part of HackRF. * diff --git a/firmware/mixertx/mixertx.c b/firmware/mixertx/mixertx.c index 600e7d6b..18415944 100644 --- a/firmware/mixertx/mixertx.c +++ b/firmware/mixertx/mixertx.c @@ -28,32 +28,6 @@ #include "max2837.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) { const uint32_t freq = 2441000000U; diff --git a/firmware/sgpio-rx/Makefile b/firmware/sgpio-rx/Makefile index 9f750ea3..db89574e 100644 --- a/firmware/sgpio-rx/Makefile +++ b/firmware/sgpio-rx/Makefile @@ -1,9 +1,30 @@ # Hey Emacs, this is a -*- makefile -*- +# +# 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. +# BINARY = sgpio-rx SRC = $(BINARY).c \ ../common/hackrf_core.c \ + ../common/sgpio.c \ ../common/si5351c.c \ ../common/max2837.c \ ../common/max5864.c \ diff --git a/firmware/sgpio-rx/sgpio-rx.c b/firmware/sgpio-rx/sgpio-rx.c index 6d56746c..ff87195b 100644 --- a/firmware/sgpio-rx/sgpio-rx.c +++ b/firmware/sgpio-rx/sgpio-rx.c @@ -30,173 +30,11 @@ #include #include #include +#include -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() { - 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) - ; - +void tx_test() { + sgpio_configure_for_tx(); + // LSB goes out first, samples are 0x volatile uint32_t buffer[] = { 0xda808080, @@ -206,8 +44,7 @@ void configure_sgpio_test_tx() { }; uint32_t i = 0; - // Enable codec data stream. - SGPIO_GPIO_OUTREG &= ~(1L << 10); + sgpio_cpld_stream_enable(); while(true) { while(SGPIO_STATUS_1 == 0); @@ -216,72 +53,15 @@ void configure_sgpio_test_tx() { } } -void configure_sgpio_test_rx() { - // Disable all counters during configuration - 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); +void rx_test() { + sgpio_configure_for_rx(); volatile uint32_t buffer[4096]; uint32_t i = 0; int16_t magsq; int8_t sigi, sigq; - // Enable codec data stream. - SGPIO_GPIO_OUTREG &= ~(1L << 10); + sgpio_cpld_stream_enable(); gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */ while(true) { @@ -317,11 +97,11 @@ int main(void) { enable_1v8_power(); cpu_clock_init(); - CGU_BASE_PERIPH_CLK = (CGU_BASE_CLK_AUTOBLOCK - | (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT)); + CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK + | CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); - CGU_BASE_APB1_CLK = (CGU_BASE_CLK_AUTOBLOCK - | (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT)); + CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK + | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); ssp1_init(); ssp1_set_mode_max2837(); @@ -339,7 +119,7 @@ int main(void) { ssp1_set_mode_max5864(); max5864_xcvr(); - configure_sgpio_test_rx(); + rx_test(); gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */ while (1) { diff --git a/firmware/sgpio/Makefile b/firmware/sgpio/Makefile index 24eefbd1..5429c192 100644 --- a/firmware/sgpio/Makefile +++ b/firmware/sgpio/Makefile @@ -1,9 +1,30 @@ # Hey Emacs, this is a -*- makefile -*- +# +# 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. +# BINARY = sgpio SRC = $(BINARY).c \ ../common/hackrf_core.c \ + ../common/sgpio.c \ ../common/si5351c.c \ ../common/max2837.c \ ../common/max5864.c diff --git a/firmware/sgpio/sgpio.c b/firmware/sgpio/sgpio.c index cc200142..88008313 100644 --- a/firmware/sgpio/sgpio.c +++ b/firmware/sgpio/sgpio.c @@ -28,172 +28,10 @@ #include #include +#include -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() { - 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) - ; +void tx_test() { + sgpio_configure_for_tx(); // LSB goes out first, samples are 0x volatile uint32_t buffer[] = { @@ -204,9 +42,8 @@ void configure_sgpio_test_tx() { }; uint32_t i = 0; - // Enable codec data stream. - SGPIO_GPIO_OUTREG &= ~(1L << 10); - + sgpio_cpld_stream_enable(); + while(true) { while(SGPIO_STATUS_1 == 0); SGPIO_REG_SS(SGPIO_SLICE_A) = buffer[(i++) & 3]; @@ -214,67 +51,13 @@ void configure_sgpio_test_tx() { } } -void configure_sgpio_test_rx() { - // Disable all counters during configuration - 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 +void rx_test() { + sgpio_configure_for_rx(); volatile uint32_t buffer[4096]; uint32_t i = 0; - // Enable codec data stream. - SGPIO_GPIO_OUTREG &= ~(1L << 10); + sgpio_cpld_stream_enable(); while(true) { while(SGPIO_STATUS_1 == 0); @@ -289,11 +72,11 @@ int main(void) { cpu_clock_init(); ssp1_init(); - CGU_BASE_PERIPH_CLK = (CGU_BASE_CLK_AUTOBLOCK - | (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT)); + CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK + | CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1); - CGU_BASE_APB1_CLK = (CGU_BASE_CLK_AUTOBLOCK - | (CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT)); + CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK + | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1); gpio_set(PORT_LED1_3, PIN_LED1); diff --git a/firmware/sgpio_passthrough_rom_to_ram/Makefile b/firmware/sgpio_passthrough_rom_to_ram/Makefile index 98eb5746..073a583b 100644 --- a/firmware/sgpio_passthrough_rom_to_ram/Makefile +++ b/firmware/sgpio_passthrough_rom_to_ram/Makefile @@ -1,4 +1,25 @@ # Hey Emacs, this is a -*- makefile -*- +# +# Copyright 2012 Jared Boone +# Copyright 2012 Benjamin Vernoux +# +# 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 diff --git a/firmware/sgpio_passthrough_rom_to_ram/sgpio_passthrough.c b/firmware/sgpio_passthrough_rom_to_ram/sgpio_passthrough.c index c5525c57..afdf8a25 100644 --- a/firmware/sgpio_passthrough_rom_to_ram/sgpio_passthrough.c +++ b/firmware/sgpio_passthrough_rom_to_ram/sgpio_passthrough.c @@ -29,52 +29,6 @@ #include -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() { scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3); scu_pinmux(SCU_PINMUX_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3); diff --git a/firmware/simpletx/simpletx.c b/firmware/simpletx/simpletx.c index 7d61cb6a..e50fbf54 100644 --- a/firmware/simpletx/simpletx.c +++ b/firmware/simpletx/simpletx.c @@ -27,32 +27,6 @@ #include "hackrf_core.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) { const uint32_t freq = 2441000000U; diff --git a/firmware/startup/startup.c b/firmware/startup/startup.c index 912ef38a..b805d1f2 100644 --- a/firmware/startup/startup.c +++ b/firmware/startup/startup.c @@ -25,37 +25,11 @@ #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) { u32 i; - gpio_setup(); + pin_setup(); gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */ diff --git a/firmware/startup_systick/startup_systick.c b/firmware/startup_systick/startup_systick.c index c7c3e01e..98b4d5b3 100644 --- a/firmware/startup_systick/startup_systick.c +++ b/firmware/startup_systick/startup_systick.c @@ -32,32 +32,6 @@ volatile u32 g_ulSysTickCount; 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) { u32 systick_reload_val; @@ -155,7 +129,7 @@ void sys_tick_handler(void) int main(void) { - gpio_setup(); + pin_setup(); gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */ diff --git a/firmware/startup_systick_perfo/startup_systick.c b/firmware/startup_systick_perfo/startup_systick.c index a8be4b05..a5bae126 100644 --- a/firmware/startup_systick_perfo/startup_systick.c +++ b/firmware/startup_systick_perfo/startup_systick.c @@ -32,32 +32,6 @@ volatile u32 g_ulSysTickCount; 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) { u32 systick_reload_val; @@ -168,7 +142,7 @@ extern u32 test_nb_instruction_per_sec_1000_nop_asm(); int main(void) { - gpio_setup(); + pin_setup(); gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */ diff --git a/firmware/startup_systick_perfo_rom_to_ram/startup_systick.c b/firmware/startup_systick_perfo_rom_to_ram/startup_systick.c index a8be4b05..a5bae126 100644 --- a/firmware/startup_systick_perfo_rom_to_ram/startup_systick.c +++ b/firmware/startup_systick_perfo_rom_to_ram/startup_systick.c @@ -32,32 +32,6 @@ volatile u32 g_ulSysTickCount; 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) { u32 systick_reload_val; @@ -168,7 +142,7 @@ extern u32 test_nb_instruction_per_sec_1000_nop_asm(); int main(void) { - gpio_setup(); + pin_setup(); gpio_set(PORT_EN1V8, PIN_EN1V8); /* 1V8 on */ diff --git a/firmware/usb_performance/Makefile b/firmware/usb_performance/Makefile new file mode 100644 index 00000000..7222a2f4 --- /dev/null +++ b/firmware/usb_performance/Makefile @@ -0,0 +1,39 @@ +# Hey Emacs, this is a -*- makefile -*- +# +# 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. +# + +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 diff --git a/firmware/usb_performance/usb.c b/firmware/usb_performance/usb.c new file mode 100644 index 00000000..535cb52d --- /dev/null +++ b/firmware/usb_performance/usb.c @@ -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 +#include + +#include "usb.h" +#include "usb_type.h" +#include "usb_standard_request.h" + +#include +#include +#include +#include + +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. + } +} diff --git a/firmware/usb_performance/usb.h b/firmware/usb_performance/usb.h new file mode 100644 index 00000000..7b9c9390 --- /dev/null +++ b/firmware/usb_performance/usb.h @@ -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 + +#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__ diff --git a/firmware/usb_performance/usb_descriptor.c b/firmware/usb_performance/usb_descriptor.c new file mode 100644 index 00000000..e27218bb --- /dev/null +++ b/firmware/usb_performance/usb_descriptor.c @@ -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 + +#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 +}; diff --git a/firmware/usb_performance/usb_descriptor.h b/firmware/usb_performance/usb_descriptor.h new file mode 100644 index 00000000..a1676f04 --- /dev/null +++ b/firmware/usb_performance/usb_descriptor.h @@ -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 + +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[]; diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c new file mode 100644 index 00000000..5a6989e3 --- /dev/null +++ b/firmware/usb_performance/usb_performance.c @@ -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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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; +} diff --git a/firmware/usb_performance/usb_request.c b/firmware/usb_performance/usb_request.c new file mode 100644 index 00000000..df6ae427 --- /dev/null +++ b/firmware/usb_performance/usb_request.c @@ -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 + +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); + } +} + diff --git a/firmware/usb_performance/usb_request.h b/firmware/usb_performance/usb_request.h new file mode 100644 index 00000000..a637924f --- /dev/null +++ b/firmware/usb_performance/usb_request.h @@ -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__ diff --git a/firmware/usb_performance/usb_standard_request.c b/firmware/usb_performance/usb_standard_request.c new file mode 100644 index 00000000..1b42bd5e --- /dev/null +++ b/firmware/usb_performance/usb_standard_request.c @@ -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 + +#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; + + } +} diff --git a/firmware/usb_performance/usb_standard_request.h b/firmware/usb_performance/usb_standard_request.h new file mode 100644 index 00000000..e96dba21 --- /dev/null +++ b/firmware/usb_performance/usb_standard_request.h @@ -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__ diff --git a/firmware/usb_performance/usb_type.h b/firmware/usb_performance/usb_type.h new file mode 100644 index 00000000..54287fd5 --- /dev/null +++ b/firmware/usb_performance/usb_type.h @@ -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 +#include + +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__ diff --git a/host/usb_test/Makefile b/host/usb_test/Makefile new file mode 100644 index 00000000..138ca744 --- /dev/null +++ b/host/usb_test/Makefile @@ -0,0 +1,77 @@ +# Hey Emacs, this is a -*- makefile -*- +# +# Copyright 2010 Michael Ossmann +# 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. +# + +# 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 \ No newline at end of file diff --git a/host/usb_test/usb_test.c b/host/usb_test/usb_test.c new file mode 100644 index 00000000..29f08a86 --- /dev/null +++ b/host/usb_test/usb_test.c @@ -0,0 +1,172 @@ +/* + * 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 +#include +#include + +#include +#include + +#include + +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 \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_indexbuffer == 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; +}