Merge pull request #104 from jboone/master

The Pull Request to End All Pull Requests
This commit is contained in:
Michael Ossmann
2014-02-19 13:17:24 -07:00
103 changed files with 5115 additions and 4831 deletions

66
.gitignore vendored Normal file
View File

@ -0,0 +1,66 @@
# Compiled output
*.bin
*.d
*.elf
*.hex
*.srec
host/build/
# Operating system spew
.DS_Store
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Editor junk
*.swp
*.sublime-project
*.sublime-workspace
# Xilinx tools create an enormous amount of poop:
firmware/cpld/**/isim/
firmware/cpld/**/_ngo/
firmware/cpld/**/_xmsgs/
firmware/cpld/**/iseconfig/
firmware/cpld/**/*_html/
firmware/cpld/**/xlnx_auto_0_xdb/
firmware/cpld/**/xst/
firmware/cpld/**/_*.cmd
firmware/cpld/**/_*.log
firmware/cpld/**/*.bld
firmware/cpld/**/*.chk
firmware/cpld/**/*.cmd
firmware/cpld/**/*.cmd_log
firmware/cpld/**/*.csv
firmware/cpld/**/*.cxt
firmware/cpld/**/*.dat
firmware/cpld/**/*.err
firmware/cpld/**/*.exe
firmware/cpld/**/*.gise
firmware/cpld/**/*.gyd
firmware/cpld/**/*.html
firmware/cpld/**/*.ini
firmware/cpld/**/*.ipf
firmware/cpld/**/*.log
firmware/cpld/**/*.lso
firmware/cpld/**/*.mfd
firmware/cpld/**/*.ng[acdr]
firmware/cpld/**/*.pad
firmware/cpld/**/*.phd
firmware/cpld/**/*.pnx
firmware/cpld/**/*.prj
firmware/cpld/**/*.rpt
firmware/cpld/**/*.stx
firmware/cpld/**/*.syr
firmware/cpld/**/*.tim
firmware/cpld/**/*.tspec
firmware/cpld/**/*.vm6
firmware/cpld/**/*.wcfg
firmware/cpld/**/*.wdb
firmware/cpld/**/*.xml
firmware/cpld/**/*.xmsgs
firmware/cpld/**/*.xrpt
firmware/cpld/**/*.xsl
firmware/cpld/**/*.xst
firmware/cpld/**/*.xwbt

View File

@ -21,7 +21,6 @@
#
TARGETS = blinky \
blinky_rom_to_ram \
mixertx \
sgpio \
sgpio-rx \
@ -29,12 +28,7 @@ TARGETS = blinky \
startup \
startup_systick \
startup_systick_perfo \
hackrf_usb \
hackrf_usb_rom_to_ram
# blinky_rom_to_ram
# sgpio_passthrough_rom_to_ram
# startup_systick_perfo_rom_to_ram
hackrf_usb
all: build

View File

@ -25,7 +25,11 @@ BINARY = blinky
SRC = $(BINARY).c \
../common/hackrf_core.c \
../common/sgpio.c \
../common/rf_path.c \
../common/si5351c.c \
../common/max2837.c
../common/max2837.c \
../common/max5864.c \
../common/rffc5071.c
include ../common/Makefile_inc.mk

View File

@ -1,3 +0,0 @@
This is the simplest example firmware for HackRF. It flashes three LEDs.
This Example Start execution in SPIFI(ROM) and at startup, code from ROM is copied to RAM and shadow pointer is modified to RAM.
So at end all the code and vector table is executed from RAM.

View File

@ -0,0 +1,34 @@
/*
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
/* Linker script for HackRF One (LPC4320, 1M SPI flash, 200K SRAM). */
MEMORY
{
/* rom is really the shadow region that points to SPI flash or elsewhere */
rom (rx) : ORIGIN = 0x00000000, LENGTH = 96K
ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 96K
ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 32K
ram_sleep (rwx) : ORIGIN = 0x10088000, LENGTH = 8K
}
INCLUDE LPC43xx_M4_memory.ld

View File

@ -20,22 +20,15 @@
* Boston, MA 02110-1301, USA.
*/
/* Linker script for HackRF Jellybean (LPC4330, 1M SPI flash, 264K SRAM). */
/* Linker script for HackRF Jellybean/Jawbreaker (LPC4330, 1M SPI flash, 264K SRAM). */
MEMORY
{
/* rom is really the shadow region that points to SPI flash or elsewhere */
rom (rx) : ORIGIN = 0x00000000, LENGTH = 1M
rom (rx) : ORIGIN = 0x00000000, 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
ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 64K
ram_sleep (rwx) : ORIGIN = 0x10090000, LENGTH = 8K
}
/* Include the common ld script. */
INCLUDE libopencm3_lpc43xx.ld
INCLUDE LPC43xx_M4_memory.ld

View File

@ -0,0 +1,26 @@
/*
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x00000000, LENGTH = 28K
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
SECTIONS
{
.text : {
PROVIDE(__m0_start__ = .);
KEEP(*(.m0_bin*));
. = ALIGN(4);
PROVIDE(__m0_end__ = .);
} >rom
}

View File

@ -1,6 +1,5 @@
/*
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF
@ -21,23 +20,17 @@
* Boston, MA 02110-1301, USA.
*/
/* Linker script for HackRF Jellybean (LPC4330, 1M SPI flash, 264K SRAM). */
MEMORY
{
/* Physical address in Flash used to copy Code from Flash to RAM */
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_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
ram_m0 (rwx) : ORIGIN = 0x20000000, LENGTH = 28K
ram_shared (rwx) : ORIGIN = 0x20007000, LENGTH = 4K
ram_usb (rwx) : ORIGIN = 0x20008000, LENGTH = 32K
/* ram_usb: 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_rom_to_ram.ld
usb_bulk_buffer = ORIGIN(ram_usb);

View File

@ -26,10 +26,16 @@
# derived primarily from Makefiles in libopencm3
#BOARD ?= JELLYBEAN
BOARD ?= JAWBREAKER
BOARD ?= HACKRF_ONE
RUN_FROM ?= SPIFI
HACKRF_OPTS = -D$(BOARD) -DLPC43XX -DLPC43XX_M4
ifeq ($(BOARD),HACKRF_ONE)
MCU_PARTNO=LPC4320
else
MCU_PARTNO=LPC4330
endif
HACKRF_OPTS = -D$(BOARD) -DLPC43XX -D$(MCU_PARTNO)
# comment to disable RF transmission
HACKRF_OPTS += -DTX_ENABLE
@ -38,9 +44,39 @@ HACKRF_OPTS += -DTX_ENABLE
VERSION_STRING ?= -D'VERSION_STRING="git-$(shell git log -n 1 --format=%h)"'
HACKRF_OPTS += $(VERSION_STRING)
LDSCRIPT ?= ../common/LPC4330_M4.ld
PATH_HACKRF ?= ../..
LIBOPENCM3 ?= ../libopencm3
PATH_HACKRF_FIRMWARE = $(PATH_HACKRF)/firmware
PATH_HACKRF_FIRMWARE_COMMON = $(PATH_HACKRF_FIRMWARE)/common
LIBOPENCM3 ?= $(PATH_HACKRF_FIRMWARE)/libopencm3
VPATH += $(PATH_HACKRF_FIRMWARE_COMMON)/xapp058
VPATH += $(PATH_HACKRF_FIRMWARE_COMMON)
SRC_M4_C ?= $(SRC)
SRC_M0_C ?= $(PATH_HACKRF_FIRMWARE_COMMON)/m0_sleep.c
BUILD_DIR = build
OBJDIR_M4 = $(BUILD_DIR)/m4
OBJDIR_M0 = $(BUILD_DIR)/m0
OBJ_M4_C = $(patsubst %.c, $(OBJDIR_M4)/%.o, $(notdir $(SRC_M4_C)))
OBJ_M4_S = $(patsubst %.s, $(OBJDIR_M4)/%.o, $(notdir $(SRC_M4_S)))
OBJ_M0_C = $(patsubst %.c, $(OBJDIR_M0)/%.o, $(notdir $(SRC_M0_C)))
OBJ_M0_S = $(patsubst %.s, $(OBJDIR_M0)/%.o, $(notdir $(SRC_M0_S)))
LDSCRIPT_M4 += -T$(PATH_HACKRF_FIRMWARE_COMMON)/$(MCU_PARTNO)_M4_memory.ld
ifeq ($(RUN_FROM),RAM)
LDSCRIPT_M4 += -Tlibopencm3_lpc43xx.ld
else
LDSCRIPT_M4 += -Tlibopencm3_lpc43xx_rom_to_ram.ld
endif
LDSCRIPT_M4 += -T$(PATH_HACKRF_FIRMWARE_COMMON)/LPC43xx_M4_M0_image_from_text.ld
LDSCRIPT_M0 += -T$(PATH_HACKRF_FIRMWARE_COMMON)/LPC43xx_M0_memory.ld
LDSCRIPT_M0 += -Tlibopencm3_lpc43xx_m0.ld
PREFIX ?= arm-none-eabi
CC = $(PREFIX)-gcc
@ -50,23 +86,34 @@ OBJDUMP = $(PREFIX)-objdump
GDB = $(PREFIX)-gdb
TOOLCHAIN_DIR := $(shell dirname `which $(CC)`)/../$(PREFIX)
CFLAGS += -std=gnu99 -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)
LDFLAGS += -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-L$(TOOLCHAIN_DIR)/lib/armv7e-m/fpu -L../common \
CFLAGS_COMMON += -std=gnu99 -Os -g3 -Wall -Wextra -I$(LIBOPENCM3)/include -I$(PATH_HACKRF_FIRMWARE_COMMON) \
$(HACKRF_OPTS) -fno-common -mthumb -MD
LDFLAGS_COMMON += -mthumb \
-L$(PATH_HACKRF_FIRMWARE_COMMON) \
-L$(LIBOPENCM3)/lib -L$(LIBOPENCM3)/lib/lpc43xx \
-T$(LDSCRIPT) -nostartfiles \
-Wl,--gc-sections -Xlinker -Map=$(BINARY).map
OBJ = $(SRC:.c=.o)
-nostartfiles \
-Wl,--gc-sections \
-lc -lnosys
CFLAGS_M0 += -mcpu=cortex-m0 -DLPC43XX_M0
LDFLAGS_M0 += -mcpu=cortex-m0 -DLPC43XX_M0
LDFLAGS_M0 += $(LDSCRIPT_M0)
LDFLAGS_M0 += --specs=nano.specs
LDFLAGS_M0 += -Xlinker -Map=$(OBJDIR_M0)/m0.map
LDFLAGS_M0 += -lopencm3_lpc43xx_m0
CFLAGS_M4 += -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -DLPC43XX_M4
LDFLAGS_M4 += -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -DLPC43XX_M4
LDFLAGS_M4 += -L$(TOOLCHAIN_DIR)/lib/armv7e-m/fpu
LDFLAGS_M4 += $(LDSCRIPT_M4)
LDFLAGS_M4 += -Xlinker -Map=$(OBJDIR_M4)/m4.map
LDFLAGS_M4 += -lopencm3_lpc43xx -lm
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
NULL := 2>/dev/null
else
LDFLAGS += -Wl,--print-gc-sections
LDFLAGS_COMMON += -Wl,--print-gc-sections
endif
.SUFFIXES: .elf .bin .hex .srec .list .images
@ -81,40 +128,77 @@ flash: $(BINARY).flash
program: $(BINARY).dfu
$(Q)dfu-util --device 1fc9:000c --alt 0 --download $(BINARY).dfu
%.images: %.bin %.hex %.srec %.list
$(BINARY).images: $(BINARY).bin $(BINARY).hex $(BINARY).srec $(BINARY).list
@#echo "*** $* images generated ***"
%.dfu: %.bin
$(BINARY).dfu: $(BINARY).bin
$(Q)rm -f _tmp.dfu _header.bin
$(Q)cp $(*).bin _tmp.dfu
$(Q)cp $(BINARY).bin _tmp.dfu
$(Q)dfu-suffix --vid=0x1fc9 --pid=0x000c --did=0x0 -s 0 -a _tmp.dfu
$(Q)python -c "import os.path; import struct; print('0000000: da ff ' + ' '.join(map(lambda s: '%02x' % ord(s), struct.pack('<H', os.path.getsize('$(*).bin') / 512 + 1))) + ' ff ff ff ff')" | xxd -g1 -r > _header.bin
$(Q)cat _header.bin _tmp.dfu >$(*).dfu
$(Q)python -c "import os.path; import struct; print('0000000: da ff ' + ' '.join(map(lambda s: '%02x' % ord(s), struct.pack('<H', os.path.getsize('$(BINARY).bin') / 512 + 1))) + ' ff ff ff ff')" | xxd -g1 -r > _header.bin
$(Q)cat _header.bin _tmp.dfu >$(BINARY).dfu
$(Q)rm -f _tmp.dfu _header.bin
%.bin: %.elf
$(BINARY).bin: $(BINARY).elf
@#printf " OBJCOPY $(*).bin\n"
$(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin
$(Q)$(OBJCOPY) -Obinary $(BINARY).elf $(BINARY).bin
%.hex: %.elf
@#printf " OBJCOPY $(*).hex\n"
$(Q)$(OBJCOPY) -Oihex $(*).elf $(*).hex
$(OBJDIR_M0)/m0.bin: $(OBJDIR_M0)/m0.elf
@#printf " OBJCOPY $(*).bin\n"
$(Q)$(OBJCOPY) -Obinary $(OBJDIR_M0)/m0.elf $(OBJDIR_M0)/m0.bin
%.srec: %.elf
@#printf " OBJCOPY $(*).srec\n"
$(Q)$(OBJCOPY) -Osrec $(*).elf $(*).srec
#$(OBJDIR_M0)/m0.o: $(OBJDIR_M0)/m0.bin
# $(Q)$(OBJCOPY) -I binary -B arm -O elf32-littlearm $(OBJDIR_M0)/m0.bin $(OBJDIR_M0)/m0.o
%.list: %.elf
@#printf " OBJDUMP $(*).list\n"
$(Q)$(OBJDUMP) -S $(*).elf > $(*).list
$(BINARY).hex: $(BINARY).elf
@#printf " OBJCOPY $(BINARY).hex\n"
$(Q)$(OBJCOPY) -Oihex $(BINARY).elf $(BINARY).hex
%.elf: $(OBJ) $(LDSCRIPT)
$(BINARY).srec: $(BINARY).elf
@#printf " OBJCOPY $(BINARY).srec\n"
$(Q)$(OBJCOPY) -Osrec $(BINARY).elf $(BINARY).srec
$(BINARY).list: $(BINARY).elf
@#printf " OBJDUMP $(BINARY).list\n"
$(Q)$(OBJDUMP) -S $(BINARY).elf > $(BINARY).list
$(BINARY).elf: obj_m4
@#printf " LD $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(LD) $(LDFLAGS) -o $(*).elf $(OBJ) -lopencm3_lpc43xx
$(Q)$(LD) -o $(BINARY).elf $(OBJ_M4_C) $(OBJ_M4_S) $(OBJDIR_M4)/m0_bin.o $(LDFLAGS_COMMON) $(LDFLAGS_M4)
%.o: %.c Makefile
@#printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
$(OBJDIR_M0)/m0.elf: obj_m0
@#printf " LD $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(LD) -o $(OBJDIR_M0)/m0.elf $(OBJ_M0_C) $(OBJ_M0_S) $(LDFLAGS_COMMON) $(LDFLAGS_M0)
obj_m4: $(OBJ_M4_C) $(OBJ_M4_S) $(OBJDIR_M4)/m0_bin.o
obj_m0: $(OBJ_M0_C) $(OBJ_M0_S)
$(OBJDIR_M4)/%.o: %.c | $(OBJDIR_M4)
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS_COMMON) $(CFLAGS_M4) -o $@ -c $<
$(OBJDIR_M4)/%.o: %.s | $(OBJDIR_M4)
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS_COMMON) $(CFLAGS_M4) -o $@ -c $<
$(OBJDIR_M4)/m0_bin.o: m0_bin.s $(OBJDIR_M0)/m0.bin | $(OBJDIR_M4)
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS_COMMON) $(CFLAGS_M4) -o $@ -c $<
$(OBJDIR_M0)/%.o: %.c | $(OBJDIR_M0)
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS_COMMON) $(CFLAGS_M0) -o $@ -c $<
$(OBJDIR_M0)/%.o: %.s | $(OBJDIR_M0)
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS_COMMON) $(CFLAGS_M0) -o $@ -c $<
$(OBJDIR_M4):
$(Q)mkdir -p $@
$(OBJDIR_M0):
$(Q)mkdir -p $@
clean:
$(Q)rm -f *.o
@ -128,12 +212,27 @@ clean:
$(Q)rm -f *.list
$(Q)rm -f *.map
$(Q)rm -f *.lst
$(Q)rm -f ../common/*.o
$(Q)rm -f ../common/*.d
$(Q)rm -f ../common/*.lst
$(Q)rm -f ../common/xapp058/*.o
$(Q)rm -f ../common/xapp058/*.d
$(Q)rm -f $(PATH_HACKRF_FIRMWARE)/hackrf_usb/*.o
$(Q)rm -f $(PATH_HACKRF_FIRMWARE)/hackrf_usb/*.d
$(Q)rm -f $(PATH_HACKRF_FIRMWARE)/hackrf_usb/*.lst
$(Q)rm -f $(PATH_HACKRF_FIRMWARE_COMMON)/*.o
$(Q)rm -f $(PATH_HACKRF_FIRMWARE_COMMON)/*.d
$(Q)rm -f $(PATH_HACKRF_FIRMWARE_COMMON)/*.lst
$(Q)rm -f $(PATH_HACKRF_FIRMWARE_COMMON)/xapp058/*.o
$(Q)rm -f $(PATH_HACKRF_FIRMWARE_COMMON)/xapp058/*.d
$(Q)rm -f $(OBJDIR_M4)/*.o
$(Q)rm -f $(OBJDIR_M4)/*.d
$(Q)rm -f $(OBJDIR_M4)/*.elf
$(Q)rm -f $(OBJDIR_M4)/*.bin
$(Q)rm -f $(OBJDIR_M4)/*.map
$(Q)rm -f $(OBJDIR_M0)/*.o
$(Q)rm -f $(OBJDIR_M0)/*.d
$(Q)rm -f $(OBJDIR_M0)/*.elf
$(Q)rm -f $(OBJDIR_M0)/*.bin
$(Q)rm -f $(OBJDIR_M0)/*.map
$(Q)rm -rf $(BUILD_DIR)
.PHONY: images clean
-include $(OBJ:.o=.d)
-include $(OBJ_M4_C:.o=.d)
-include $(OBJ_M0_C:.o=.d)

View File

@ -26,8 +26,9 @@
#include <libopencm3/lpc43xx/scu.h>
#include <stdint.h>
uint32_t xsvf_len;
unsigned char* xsvf_data;
static refill_buffer_cb refill_buffer;
static uint32_t xsvf_buffer_len, xsvf_pos;
static unsigned char* xsvf_buffer;
void cpld_jtag_setup(void) {
scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4);
@ -58,11 +59,16 @@ void cpld_jtag_release(void) {
}
/* return 0 if success else return error code see xsvfExecute() */
int cpld_jtag_program(const uint32_t len, unsigned char* const data) {
int cpld_jtag_program(
const uint32_t buffer_length,
unsigned char* const buffer,
refill_buffer_cb refill
) {
int error;
cpld_jtag_setup();
xsvf_data = data;
xsvf_len = len;
xsvf_buffer = buffer;
xsvf_buffer_len = buffer_length;
refill_buffer = refill;
error = xsvfExecute();
cpld_jtag_release();
@ -71,12 +77,12 @@ int cpld_jtag_program(const uint32_t len, unsigned char* const data) {
/* this gets called by the XAPP058 code */
unsigned char cpld_jtag_get_next_byte(void) {
unsigned char byte = *xsvf_data;
if (xsvf_len > 1) {
xsvf_data++;
xsvf_len--;
}
if (xsvf_pos == xsvf_buffer_len) {
refill_buffer();
xsvf_pos = 0;
}
unsigned char byte = xsvf_buffer[xsvf_pos];
xsvf_pos++;
return byte;
}

View File

@ -24,9 +24,20 @@
#include <stdint.h>
typedef void (*refill_buffer_cb)(void);
void cpld_jtag_release(void);
/* return 0 if success else return error code see xsvfExecute() see micro.h */
int cpld_jtag_program(const uint32_t len, unsigned char* const data);
/* Return 0 if success else return error code see xsvfExecute() see micro.h.
*
* We expect the buffer to be initially full of data. After the entire
* contents of the buffer has been streamed to the CPLD the given
* refill_buffer callback will be called. */
int cpld_jtag_program(
const uint32_t buffer_length,
unsigned char* const buffer,
refill_buffer_cb refill
);
unsigned char cpld_jtag_get_next_byte(void);
#endif//__CPLD_JTAG_H__

62
firmware/common/gpdma.c Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright 2013 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <gpdma.h>
#include <libopencm3/lpc43xx/gpdma.h>
void gpdma_controller_enable() {
GPDMA_CONFIG |= GPDMA_CONFIG_E(1);
while( (GPDMA_CONFIG & GPDMA_CONFIG_E_MASK) == 0 );
}
void gpdma_channel_enable(const uint_fast8_t channel) {
GPDMA_CCONFIG(channel) |= GPDMA_CCONFIG_E(1);
}
void gpdma_channel_disable(const uint_fast8_t channel) {
GPDMA_CCONFIG(channel) &= ~GPDMA_CCONFIG_E_MASK;
while( (GPDMA_ENBLDCHNS & GPDMA_ENBLDCHNS_ENABLEDCHANNELS(1 << channel)) );
}
void gpdma_channel_interrupt_tc_clear(const uint_fast8_t channel) {
GPDMA_INTTCCLEAR = GPDMA_INTTCCLEAR_INTTCCLEAR(1 << channel);
}
void gpdma_channel_interrupt_error_clear(const uint_fast8_t channel) {
GPDMA_INTERRCLR = GPDMA_INTERRCLR_INTERRCLR(1 << channel);
}
void gpdma_lli_enable_interrupt(gpdma_lli_t* const lli) {
lli->ccontrol |= GPDMA_CCONTROL_I(1);
}
void gpdma_lli_create_loop(gpdma_lli_t* const lli, const size_t lli_count) {
for(size_t i=0; i<lli_count; i++) {
gpdma_lli_t* const next_lli = &lli[(i + 1) % lli_count];
lli[i].clli = (lli[i].clli & ~GPDMA_CLLI_LLI_MASK) | GPDMA_CLLI_LLI((uint32_t)next_lli >> 2);
}
}
void gpdma_lli_create_oneshot(gpdma_lli_t* const lli, const size_t lli_count) {
gpdma_lli_create_loop(lli, lli_count);
lli[lli_count - 1].clli &= ~GPDMA_CLLI_LLI_MASK;
}

43
firmware/common/gpdma.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright 2013 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GPDMA_H__
#define __GPDMA_H__
#include <stddef.h>
#include <stdint.h>
#include <libopencm3/lpc43xx/gpdma.h>
void gpdma_controller_enable();
void gpdma_channel_enable(const uint_fast8_t channel);
void gpdma_channel_disable(const uint_fast8_t channel);
void gpdma_channel_interrupt_tc_clear(const uint_fast8_t channel);
void gpdma_channel_interrupt_error_clear(const uint_fast8_t channel);
void gpdma_lli_enable_interrupt(gpdma_lli_t* const lli);
void gpdma_lli_create_loop(gpdma_lli_t* const lli, const size_t lli_count);
void gpdma_lli_create_oneshot(gpdma_lli_t* const lli, const size_t lli_count);
#endif/*__GPDMA_H__*/

View File

@ -25,12 +25,16 @@
#include "si5351c.h"
#include "max2837.h"
#include "rffc5071.h"
#include "sgpio.h"
#include "rf_path.h"
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/ssp.h>
#define WAIT_CPU_CLOCK_INIT_DELAY (10000)
void delay(uint32_t duration)
{
uint32_t i;
@ -186,16 +190,32 @@ bool sample_rate_set(const uint32_t sample_rate_hz) {
#if (defined JAWBREAKER || defined HACKRF_ONE)
uint32_t p1 = 4608;
uint32_t p2 = 0;
uint32_t p3 = 0;
switch(sample_rate_hz) {
case 8000000:
p1 = SI_INTDIV(50); // 800MHz / 50 = 16 MHz (SGPIO), 8 MHz (codec)
break;
case 9216000:
// 43.40277777777778: a = 43; b = 29; c = 72
p1 = 5043;
p2 = 40;
p3 = 72;
break;
case 10000000:
p1 = SI_INTDIV(40); // 800MHz / 40 = 20 MHz (SGPIO), 10 MHz (codec)
break;
case 12288000:
// 32.552083333333336: a = 32; b = 159; c = 288
p1 = 3654;
p2 = 192;
p3 = 288;
break;
case 12500000:
p1 = SI_INTDIV(32); // 800MHz / 32 = 25 MHz (SGPIO), 12.5 MHz (codec)
break;
@ -204,6 +224,13 @@ bool sample_rate_set(const uint32_t sample_rate_hz) {
p1 = SI_INTDIV(25); // 800MHz / 25 = 32 MHz (SGPIO), 16 MHz (codec)
break;
case 18432000:
// 21.70138888889: a = 21; b = 101; c = 144
p1 = 2265;
p2 = 112;
p3 = 144;
break;
case 20000000:
p1 = SI_INTDIV(20); // 800MHz / 20 = 40 MHz (SGPIO), 20 MHz (codec)
break;
@ -213,7 +240,7 @@ bool sample_rate_set(const uint32_t sample_rate_hz) {
}
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(0, p1, 0, 1, 1);
si5351c_configure_multisynth(0, p1, p2, p3, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(1, p1, 0, 1, 0);//p1 doesn't matter
@ -232,7 +259,9 @@ bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) {
return max2837_set_lpf_bandwidth(bandwidth_hz);
}
/* clock startup for Jellybean with Lemondrop attached */
/* clock startup for Jellybean with Lemondrop attached
Configure PLL1 to max speed (204MHz).
Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. */
void cpu_clock_init(void)
{
/* use IRC as clock source for APB1 (including I2C0) */
@ -290,9 +319,10 @@ void cpu_clock_init(void)
/* MS5/CLK5 is the source for the MAX2837 clock input. */
si5351c_configure_multisynth(5, 20*128-512, 0, 1, 0); /* 800/20 = 40MHz */
/* MS6/CLK6 is unused. */
/* MS7/CLK7 is the source for the LPC43xx microcontroller. */
//uint8_t ms7data[] = { 91, 40, 0x0 };
//si5351c_write(ms7data, sizeof(ms7data));
uint8_t ms7data[] = { 90, 255, 20, 0 };
si5351c_write(ms7data, sizeof(ms7data));
#endif
/* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */
@ -323,76 +353,149 @@ void cpu_clock_init(void)
#endif
/* set xtal oscillator to low frequency mode */
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF;
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK;
/* power on the oscillator and wait until stable */
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE;
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK;
/* Wait about 100us after Crystal Power ON */
delay(WAIT_CPU_CLOCK_INIT_DELAY);
/* use XTAL_OSC as clock source for BASE_M4_CLK (CPU) */
CGU_BASE_M4_CLK = CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_XTAL);
CGU_BASE_M4_CLK = (CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_XTAL) | CGU_BASE_M4_CLK_AUTOBLOCK(1));
/* use XTAL_OSC as clock source for APB1 */
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK(1)
| CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL);
/* use XTAL_OSC as clock source for PLL1 */
/* Start PLL1 at 12MHz * 17 / (2+2) = 51MHz. */
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));
cpu_clock_pll1_low_speed();
/* use PLL1 as clock source for BASE_M4_CLK (CPU) */
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)
| CGU_PLL1_CTRL_FBSEL;
//| CGU_PLL1_CTRL_DIRECT;
/* wait until stable */
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK));
CGU_BASE_M4_CLK = (CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1) | CGU_BASE_M4_CLK_AUTOBLOCK(1));
/* use XTAL_OSC as clock source for PLL0USB */
CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD
| CGU_PLL0USB_CTRL_AUTOBLOCK
CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1)
| CGU_PLL0USB_CTRL_AUTOBLOCK(1)
| CGU_PLL0USB_CTRL_CLK_SEL(CGU_SRC_XTAL);
while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK);
while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK);
/* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */
/* 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
| CGU_PLL0USB_CTRL_CLKEN);
CGU_PLL0USB_CTRL |= (CGU_PLL0USB_CTRL_PD(1)
| CGU_PLL0USB_CTRL_DIRECTI(1)
| CGU_PLL0USB_CTRL_DIRECTO(1)
| CGU_PLL0USB_CTRL_CLKEN(1));
/* power on PLL0USB and wait until stable */
CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD;
while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK));
CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD_MASK;
while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK));
/* use PLL0USB as clock source for USB0 */
CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK
CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK(1)
| CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB);
/* Switch peripheral clock over to use PLL1 (204MHz) */
CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK
CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK(1)
| CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1);
/* Switch APB1 clock over to use PLL1 (204MHz) */
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_AUTOBLOCK(1)
| CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1);
}
/*
Configure PLL1 to low speed (48MHz).
Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1.
This function shall be called after cpu_clock_init().
This function is mainly used to lower power consumption.
*/
void cpu_clock_pll1_low_speed(void)
{
uint32_t pll_reg;
/* Configure PLL1 Clock (48MHz) */
/* Integer mode:
FCLKOUT = M*(FCLKIN/N)
FCCO = 2*P*FCLKOUT = 2*P*M*(FCLKIN/N)
*/
pll_reg = CGU_PLL1_CTRL;
/* Clear PLL1 bits */
pll_reg &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | CGU_PLL1_CTRL_PD_MASK | CGU_PLL1_CTRL_FBSEL_MASK | /* CLK SEL, PowerDown , FBSEL */
CGU_PLL1_CTRL_BYPASS_MASK | /* BYPASS */
CGU_PLL1_CTRL_DIRECT_MASK | /* DIRECT */
CGU_PLL1_CTRL_PSEL_MASK | CGU_PLL1_CTRL_MSEL_MASK | CGU_PLL1_CTRL_NSEL_MASK ); /* PSEL, MSEL, NSEL- divider ratios */
/* Set PLL1 up to 12MHz * 4 = 48MHz. */
pll_reg |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL)
| CGU_PLL1_CTRL_PSEL(0)
| CGU_PLL1_CTRL_NSEL(0)
| CGU_PLL1_CTRL_MSEL(3)
| CGU_PLL1_CTRL_FBSEL(1)
| CGU_PLL1_CTRL_DIRECT(1);
CGU_PLL1_CTRL = pll_reg;
/* wait until stable */
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK));
/* Wait a delay after switch to new frequency with Direct mode */
delay(WAIT_CPU_CLOCK_INIT_DELAY);
}
/*
Configure PLL1 (Main MCU Clock) to max speed (204MHz).
Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1.
This function shall be called after cpu_clock_init().
*/
void cpu_clock_pll1_max_speed(void)
{
uint32_t pll_reg;
/* Configure PLL1 to Intermediate Clock (between 90 MHz and 110 MHz) */
/* Integer mode:
FCLKOUT = M*(FCLKIN/N)
FCCO = 2*P*FCLKOUT = 2*P*M*(FCLKIN/N)
*/
pll_reg = CGU_PLL1_CTRL;
/* Clear PLL1 bits */
pll_reg &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | CGU_PLL1_CTRL_PD_MASK | CGU_PLL1_CTRL_FBSEL_MASK | /* CLK SEL, PowerDown , FBSEL */
CGU_PLL1_CTRL_BYPASS_MASK | /* BYPASS */
CGU_PLL1_CTRL_DIRECT_MASK | /* DIRECT */
CGU_PLL1_CTRL_PSEL_MASK | CGU_PLL1_CTRL_MSEL_MASK | CGU_PLL1_CTRL_NSEL_MASK ); /* PSEL, MSEL, NSEL- divider ratios */
/* Set PLL1 up to 12MHz * 8 = 96MHz. */
pll_reg |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL)
| CGU_PLL1_CTRL_PSEL(0)
| CGU_PLL1_CTRL_NSEL(0)
| CGU_PLL1_CTRL_MSEL(7)
| CGU_PLL1_CTRL_FBSEL(1);
CGU_PLL1_CTRL = pll_reg;
/* wait until stable */
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK));
/* Wait before to switch to max speed */
delay(WAIT_CPU_CLOCK_INIT_DELAY);
/* Configure PLL1 Max Speed */
/* Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */
pll_reg = CGU_PLL1_CTRL;
/* Clear PLL1 bits */
pll_reg &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK | CGU_PLL1_CTRL_PD_MASK | CGU_PLL1_CTRL_FBSEL_MASK | /* CLK SEL, PowerDown , FBSEL */
CGU_PLL1_CTRL_BYPASS_MASK | /* BYPASS */
CGU_PLL1_CTRL_DIRECT_MASK | /* DIRECT */
CGU_PLL1_CTRL_PSEL_MASK | CGU_PLL1_CTRL_MSEL_MASK | CGU_PLL1_CTRL_NSEL_MASK ); /* PSEL, MSEL, NSEL- divider ratios */
/* Set PLL1 up to 12MHz * 17 = 204MHz. */
pll_reg |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL)
| CGU_PLL1_CTRL_PSEL(0)
| CGU_PLL1_CTRL_NSEL(0)
| CGU_PLL1_CTRL_MSEL(16)
| CGU_PLL1_CTRL_FBSEL(1)
| CGU_PLL1_CTRL_DIRECT(1);
CGU_PLL1_CTRL = pll_reg;
/* wait until stable */
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK));
}
void ssp1_init(void)
{
/*
@ -487,26 +590,6 @@ void pin_setup(void) {
scu_pinmux(SCU_PINMUX_USB_LED0, SCU_CONF_FUNCTION3);
scu_pinmux(SCU_PINMUX_USB_LED1, SCU_CONF_FUNCTION3);
#ifdef HACKRF_ONE
/* Configure RF switch control signals */
scu_pinmux(SCU_HP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_LP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_TX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_NO_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_RX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_TX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_NO_TX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_AMP_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_RX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
/* Configure RF power supply (VAA) switch */
scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
#endif
/* Configure all GPIO as Input (safe state) */
GPIO0_DIR = 0;
GPIO1_DIR = 0;
@ -523,27 +606,8 @@ void pin_setup(void) {
/* GPIO3[6] on P6_10 as output. */
GPIO3_DIR |= PIN_EN1V8;
#ifdef HACKRF_ONE
/* Configure RF switch control signals as outputs */
GPIO0_DIR |= PIN_AMP_BYPASS;
GPIO1_DIR |= (PIN_NO_MIX_BYPASS | PIN_RX_AMP | PIN_NO_RX_AMP_PWR);
GPIO2_DIR |= (PIN_HP | PIN_LP | PIN_TX_MIX_BP | PIN_RX_MIX_BP | PIN_TX_AMP);
GPIO3_DIR |= PIN_NO_TX_AMP_PWR;
GPIO5_DIR |= (PIN_TX | PIN_MIX_BYPASS | PIN_RX);
/*
* Safe (initial) switch settings turn off both amplifiers and enable both
* amp bypass and mixer bypass.
*/
switchctrl_set(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS);
/* Configure RF power supply (VAA) switch control signal as output */
GPIO_DIR(PORT_NO_VAA_ENABLE) |= PIN_NO_VAA_ENABLE;
/* Safe state: start with VAA turned off: */
disable_rf_power();
#endif
rf_path_pin_setup();
/* 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));
@ -551,7 +615,9 @@ void pin_setup(void) {
scu_pinmux(SCU_SSP1_SSEL, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
/* Configure external clock in */
//scu_pinmux(P4_7, SCU_CLK_IN | SCU_CONF_FUNCTION1);
scu_pinmux(SCU_PINMUX_GP_CLKIN, SCU_CLK_IN | SCU_CONF_FUNCTION1);
sgpio_configure_pin_functions();
}
void enable_1v8_power(void) {
@ -570,69 +636,4 @@ void enable_rf_power(void) {
void disable_rf_power(void) {
gpio_set(PORT_NO_VAA_ENABLE, PIN_NO_VAA_ENABLE);
}
void switchctrl_set(uint8_t ctrl) {
if (ctrl & SWITCHCTRL_TX) {
gpio_set(PORT_TX, PIN_TX);
gpio_clear(PORT_RX, PIN_RX);
} else {
gpio_clear(PORT_TX, PIN_TX);
gpio_set(PORT_RX, PIN_RX);
}
if (ctrl & SWITCHCTRL_MIX_BYPASS) {
gpio_set(PORT_MIX_BYPASS, PIN_MIX_BYPASS);
gpio_clear(PORT_NO_MIX_BYPASS, PIN_NO_MIX_BYPASS);
if (ctrl & SWITCHCTRL_TX) {
gpio_set(PORT_TX_MIX_BP, PIN_TX_MIX_BP);
gpio_clear(PORT_RX_MIX_BP, PIN_RX_MIX_BP);
} else {
gpio_clear(PORT_TX_MIX_BP, PIN_TX_MIX_BP);
gpio_set(PORT_RX_MIX_BP, PIN_RX_MIX_BP);
}
} else {
gpio_clear(PORT_MIX_BYPASS, PIN_MIX_BYPASS);
gpio_set(PORT_NO_MIX_BYPASS, PIN_NO_MIX_BYPASS);
gpio_clear(PORT_TX_MIX_BP, PIN_TX_MIX_BP);
gpio_clear(PORT_RX_MIX_BP, PIN_RX_MIX_BP);
}
if (ctrl & SWITCHCTRL_HP) {
gpio_set(PORT_HP, PIN_HP);
gpio_clear(PORT_LP, PIN_LP);
} else {
gpio_clear(PORT_HP, PIN_HP);
gpio_set(PORT_LP, PIN_LP);
}
if (ctrl & SWITCHCTRL_AMP_BYPASS) {
gpio_set(PORT_AMP_BYPASS, PIN_AMP_BYPASS);
gpio_clear(PORT_TX_AMP, PIN_TX_AMP);
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
gpio_clear(PORT_RX_AMP, PIN_RX_AMP);
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
} else if (ctrl & SWITCHCTRL_TX) {
gpio_clear(PORT_AMP_BYPASS, PIN_AMP_BYPASS);
gpio_set(PORT_TX_AMP, PIN_TX_AMP);
gpio_clear(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
gpio_clear(PORT_RX_AMP, PIN_RX_AMP);
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
} else {
gpio_clear(PORT_AMP_BYPASS, PIN_AMP_BYPASS);
gpio_clear(PORT_TX_AMP, PIN_TX_AMP);
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
gpio_set(PORT_RX_AMP, PIN_RX_AMP);
gpio_clear(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
}
/*
* These normally shouldn't be set post-Jawbreaker, but they can be
* used to explicitly turn off power to the amplifiers while AMP_BYPASS
* is unset:
*/
if (ctrl & SWITCHCTRL_NO_TX_AMP_PWR)
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR)
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
}
#endif

View File

@ -79,8 +79,13 @@ extern "C"
/* CPLD JTAG interface */
#define SCU_PINMUX_CPLD_TDO (P9_5) /* GPIO5[18] */
#define SCU_PINMUX_CPLD_TCK (P6_1) /* GPIO3[ 0] */
#ifdef HACKRF_ONE
#define SCU_PINMUX_CPLD_TMS (P6_5) /* GPIO3[ 4] */
#define SCU_PINMUX_CPLD_TDI (P6_2) /* GPIO3[ 1] */
#else
#define SCU_PINMUX_CPLD_TMS (P6_2) /* GPIO3[ 1] */
#define SCU_PINMUX_CPLD_TDI (P6_5) /* GPIO3[ 4] */
#endif
/* CPLD SGPIO interface */
#define SCU_PINMUX_SGPIO0 (P0_0)
@ -173,6 +178,32 @@ extern "C"
#define SCU_NO_RX_AMP_PWR (P2_12) /* GPIO1[12] on P2_12 */
#endif
/* TODO add other Pins */
#define SCU_PINMUX_GPIO3_8 (P7_0) /* GPIO3[8] */
#define SCU_PINMUX_GPIO3_9 (P7_1) /* GPIO3[9] */
#define SCU_PINMUX_GPIO3_10 (P7_2) /* GPIO3[10] */
#define SCU_PINMUX_GPIO3_11 (P7_3) /* GPIO3[11] */
#define SCU_PINMUX_GPIO3_12 (P7_4) /* GPIO3[12] */
#define SCU_PINMUX_GPIO3_13 (P7_5) /* GPIO3[13] */
#define SCU_PINMUX_GPIO3_14 (P7_6) /* GPIO3[14] */
#define SCU_PINMUX_GPIO3_15 (P7_7) /* GPIO3[15] */
#define SCU_PINMUX_SD_POW (P1_5) /* GPIO1[8] */
#define SCU_PINMUX_SD_CMD (P1_6) /* GPIO1[9] */
#define SCU_PINMUX_SD_VOLT0 (P1_8) /* GPIO1[1] */
#define SCU_PINMUX_SD_DAT0 (P1_9) /* GPIO1[2] */
#define SCU_PINMUX_SD_DAT1 (P1_10) /* GPIO1[3] */
#define SCU_PINMUX_SD_DAT2 (P1_11) /* GPIO1[4] */
#define SCU_PINMUX_SD_DAT3 (P1_12) /* GPIO1[5] */
#define SCU_PINMUX_SD_CD (P1_13) /* GPIO1[6] */
#define SCU_PINMUX_U0_TXD (P2_0) /* GPIO5[0] */
#define SCU_PINMUX_U0_RXD (P2_1) /* GPIO5[1] */
#define SCU_PINMUX_ISP (P2_7) /* GPIO0[7] */
#define SCU_PINMUX_GP_CLKIN (P4_7)
/*
* GPIO Pins
*/
@ -286,11 +317,18 @@ extern "C"
#define PORT_CPLD_TDO (GPIO5)
#define PIN_CPLD_TCK (GPIOPIN0)
#define PORT_CPLD_TCK (GPIO3)
#ifdef HACKRF_ONE
#define PIN_CPLD_TMS (GPIOPIN4)
#define PORT_CPLD_TMS (GPIO3)
#define PIN_CPLD_TDI (GPIOPIN1)
#define PORT_CPLD_TDI (GPIO3)
#else
#define PIN_CPLD_TMS (GPIOPIN1)
#define PORT_CPLD_TMS (GPIO3)
#define PIN_CPLD_TDI (GPIOPIN4)
#define PORT_CPLD_TDI (GPIO3)
#endif
/* Read GPIO Pin */
#define GPIO_STATE(port, pin) ((GPIO_PIN(port) & (pin)) == (pin))
#define BOOT0_STATE GPIO_STATE(GPIO0, PIN_BOOT0)
@ -300,27 +338,7 @@ extern "C"
#define MIXER_SDATA_STATE GPIO_STATE(PORT_MIXER_SDATA, PIN_MIXER_SDATA)
#define CPLD_TDO_STATE GPIO_STATE(PORT_CPLD_TDO, PIN_CPLD_TDO)
/*
* RF switches on Jawbreaker are controlled by General Purpose Outputs (GPO) on
* the RFFC5072.
*
* On HackRF One, the same signals are controlled by GPIO on the LPC.
* SWITCHCTRL_NO_TX_AMP_PWR and SWITCHCTRL_NO_RX_AMP_PWR are not normally used
* on HackRF One as the amplifier power is instead controlled only by
* SWITCHCTRL_AMP_BYPASS.
*/
#define SWITCHCTRL_NO_TX_AMP_PWR (1 << 0) /* GPO1 turn off TX amp power */
#define SWITCHCTRL_AMP_BYPASS (1 << 1) /* GPO2 bypass amp section */
#define SWITCHCTRL_TX (1 << 2) /* GPO3 1 for TX mode, 0 for RX mode */
#define SWITCHCTRL_MIX_BYPASS (1 << 3) /* GPO4 bypass RFFC5072 mixer section */
#define SWITCHCTRL_HP (1 << 4) /* GPO5 1 for high-pass, 0 for low-pass */
#define SWITCHCTRL_NO_RX_AMP_PWR (1 << 5) /* GPO6 turn off RX amp power */
/*
* Safe (initial) switch settings turn off both amplifiers and enable both amp
* bypass and mixer bypass.
*/
#define SWITCHCTRL_SAFE (SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_TX | SWITCHCTRL_MIX_BYPASS | SWITCHCTRL_HP | SWITCHCTRL_NO_RX_AMP_PWR)
/* TODO add other Pins */
typedef enum {
TRANSCEIVER_MODE_OFF = 0,
@ -331,6 +349,8 @@ typedef enum {
void delay(uint32_t duration);
void cpu_clock_init(void);
void cpu_clock_pll1_low_speed(void);
void cpu_clock_pll1_max_speed(void);
void ssp1_init(void);
void ssp1_set_mode_max2837(void);
void ssp1_set_mode_max5864(void);
@ -347,7 +367,6 @@ bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz);
#ifdef HACKRF_ONE
void enable_rf_power(void);
void disable_rf_power(void);
void switchctrl_set(uint8_t ctrl);
#endif
#ifdef __cplusplus

View File

@ -1,6 +1,4 @@
# Hey Emacs, this is a -*- makefile -*-
#
# Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
# Copyright 2013 Jared Boone <jared@sharebrained.com>
#
# This file is part of HackRF.
#
@ -18,21 +16,8 @@
# 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_rom_to_ram
SRC_DIR = blinky
SRC = blinky.c \
../common/hackrf_core.c \
../common/si5351c.c \
../common/max2837.c
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
%.o: ../$(SRC_DIR)/%.c Makefile
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
include ../common/Makefile_inc.mk
.data
.section .m0_bin, "ax"
.incbin "build/m0/m0.bin"

View File

@ -0,0 +1,26 @@
/*
* Copyright 2013 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
int main() {
while(1) {
}
}

View File

@ -116,9 +116,7 @@ void max2837_setup(void)
;
#endif
/* disable everything */
gpio_clear(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
max2837_mode_shutdown();
#ifdef JELLYBEAN
gpio_set(PORT_XCVR_RXHP, PIN_XCVR_RXHP);
gpio_set(PORT_XCVR_B,
@ -220,14 +218,90 @@ void max2837_regs_commit(void)
}
}
void max2837_mode_shutdown(void) {
/* All circuit blocks are powered down, except the 4-wire serial bus
* and its internal programmable registers.
*/
gpio_clear(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
}
void max2837_mode_standby(void) {
/* Used to enable the frequency synthesizer block while the rest of the
* device is powered down. In this mode, PLL, VCO, and LO generator
* are on, so that Tx or Rx modes can be quickly enabled from this mode.
* These and other blocks can be selectively enabled in this mode.
*/
gpio_clear(PORT_XCVR_ENABLE, (PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
gpio_set(PORT_XCVR_ENABLE, PIN_XCVR_ENABLE);
}
void max2837_mode_tx(void) {
/* All Tx circuit blocks are powered on. The external PA is powered on
* after a programmable delay using the on-chip PA bias DAC. The slow-
* charging Rx circuits are in a precharged idle-off state for fast
* Tx-to-Rx turnaround time.
*/
gpio_clear(PORT_XCVR_ENABLE, PIN_XCVR_RXENABLE);
gpio_set(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_TXENABLE));
}
void max2837_mode_rx(void) {
/* All Rx circuit blocks are powered on and active. Antenna signal is
* applied; RF is downconverted, filtered, and buffered at Rx BB I and Q
* outputs. The slow- charging Tx circuits are in a precharged idle-off
* state for fast Rx-to-Tx turnaround time.
*/
gpio_clear(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE);
gpio_set(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE));
}
max2837_mode_t max2837_mode(void) {
if( gpio_get(PORT_XCVR_ENABLE, PIN_XCVR_ENABLE) ) {
if( gpio_get(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE) ) {
return MAX2837_MODE_TX;
} else if( gpio_get(PORT_XCVR_ENABLE, PIN_XCVR_RXENABLE) ) {
return MAX2837_MODE_RX;
} else {
return MAX2837_MODE_STANDBY;
}
} else {
return MAX2837_MODE_SHUTDOWN;
}
}
void max2837_set_mode(const max2837_mode_t new_mode) {
switch(new_mode) {
case MAX2837_MODE_SHUTDOWN:
max2837_mode_shutdown();
break;
case MAX2837_MODE_STANDBY:
max2837_mode_standby();
break;
case MAX2837_MODE_TX:
max2837_mode_tx();
break;
case MAX2837_MODE_RX:
max2837_mode_rx();
break;
default:
break;
}
}
void max2837_start(void)
{
LOG("# max2837_start\n");
set_MAX2837_EN_SPI(1);
max2837_regs_commit();
#if !defined TEST
gpio_clear(PORT_XCVR_ENABLE, (PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
gpio_set(PORT_XCVR_ENABLE, PIN_XCVR_ENABLE);
max2837_mode_standby();
#endif
}
@ -238,9 +312,7 @@ void max2837_tx(void)
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_TxLPF);
max2837_regs_commit();
gpio_clear(PORT_XCVR_ENABLE, PIN_XCVR_RXENABLE);
gpio_set(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE);
max2837_mode_tx();
#endif
}
@ -252,8 +324,7 @@ void max2837_rx(void)
max2837_regs_commit();
#if !defined TEST
gpio_clear(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE);
gpio_set(PORT_XCVR_ENABLE, PIN_XCVR_RXENABLE);
max2837_mode_rx();
#endif
}
@ -263,8 +334,7 @@ void max2837_stop(void)
set_MAX2837_EN_SPI(0);
max2837_regs_commit();
#if !defined TEST
gpio_clear(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
max2837_mode_shutdown();
#endif
}

View File

@ -37,6 +37,21 @@ extern void max2837_regs_read(void);
* provided routines for those operations. */
extern void max2837_regs_commit(void);
typedef enum {
MAX2837_MODE_SHUTDOWN,
MAX2837_MODE_STANDBY,
MAX2837_MODE_TX,
MAX2837_MODE_RX
} max2837_mode_t;
void max2837_mode_shutdown(void);
void max2837_mode_standby(void);
void max2837_mode_tx(void);
void max2837_mode_rx(void);
max2837_mode_t max2837_mode(void);
void max2837_set_mode(const max2837_mode_t new_mode);
/* Turn on/off all chip functions. Does not control oscillator and CLKOUT */
extern void max2837_start(void);
extern void max2837_stop(void);

306
firmware/common/rf_path.c Normal file
View File

@ -0,0 +1,306 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "rf_path.h"
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <hackrf_core.h>
#include <rffc5071.h>
#include <max2837.h>
#include <max5864.h>
#include <sgpio.h>
#if (defined JAWBREAKER || defined HACKRF_ONE)
/*
* RF switches on Jawbreaker are controlled by General Purpose Outputs (GPO) on
* the RFFC5072.
*
* On HackRF One, the same signals are controlled by GPIO on the LPC.
* SWITCHCTRL_NO_TX_AMP_PWR and SWITCHCTRL_NO_RX_AMP_PWR are not normally used
* on HackRF One as the amplifier power is instead controlled only by
* SWITCHCTRL_AMP_BYPASS.
*/
#define SWITCHCTRL_NO_TX_AMP_PWR (1 << 0) /* GPO1 turn off TX amp power */
#define SWITCHCTRL_AMP_BYPASS (1 << 1) /* GPO2 bypass amp section */
#define SWITCHCTRL_TX (1 << 2) /* GPO3 1 for TX mode, 0 for RX mode */
#define SWITCHCTRL_MIX_BYPASS (1 << 3) /* GPO4 bypass RFFC5072 mixer section */
#define SWITCHCTRL_HP (1 << 4) /* GPO5 1 for high-pass, 0 for low-pass */
#define SWITCHCTRL_NO_RX_AMP_PWR (1 << 5) /* GPO6 turn off RX amp power */
/*
GPO6 GPO5 GPO4 GPO3 GPO2 GPO1
!RXAMP HP MIXBP TX AMPBP !TXAMP Mix mode Amp mode
1 X 1 1 1 1 TX bypass Bypass
1 X 1 1 0 0 TX bypass TX amplified
1 1 0 1 1 1 TX high Bypass
1 1 0 1 0 0 TX high TX amplified
1 0 0 1 1 1 TX low Bypass
1 0 0 1 0 0 TX low TX amplified
1 X 1 0 1 1 RX bypass Bypass
0 X 1 0 0 1 RX bypass RX amplified
1 1 0 0 1 1 RX high Bypass
0 1 0 0 0 1 RX high RX amplified
1 0 0 0 1 1 RX low Bypass
0 0 0 0 0 1 RX low RX amplified
*/
/*
* Safe (initial) switch settings turn off both amplifiers and enable both amp
* bypass and mixer bypass.
*/
#define SWITCHCTRL_SAFE (SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_TX | SWITCHCTRL_MIX_BYPASS | SWITCHCTRL_HP | SWITCHCTRL_NO_RX_AMP_PWR)
#endif
uint8_t switchctrl = SWITCHCTRL_SAFE;
#ifdef HACKRF_ONE
static void switchctrl_set_hackrf_one(uint8_t ctrl) {
if (ctrl & SWITCHCTRL_TX) {
gpio_set(PORT_TX, PIN_TX);
gpio_clear(PORT_RX, PIN_RX);
} else {
gpio_clear(PORT_TX, PIN_TX);
gpio_set(PORT_RX, PIN_RX);
}
if (ctrl & SWITCHCTRL_MIX_BYPASS) {
gpio_set(PORT_MIX_BYPASS, PIN_MIX_BYPASS);
gpio_clear(PORT_NO_MIX_BYPASS, PIN_NO_MIX_BYPASS);
if (ctrl & SWITCHCTRL_TX) {
gpio_set(PORT_TX_MIX_BP, PIN_TX_MIX_BP);
gpio_clear(PORT_RX_MIX_BP, PIN_RX_MIX_BP);
} else {
gpio_clear(PORT_TX_MIX_BP, PIN_TX_MIX_BP);
gpio_set(PORT_RX_MIX_BP, PIN_RX_MIX_BP);
}
} else {
gpio_clear(PORT_MIX_BYPASS, PIN_MIX_BYPASS);
gpio_set(PORT_NO_MIX_BYPASS, PIN_NO_MIX_BYPASS);
gpio_clear(PORT_TX_MIX_BP, PIN_TX_MIX_BP);
gpio_clear(PORT_RX_MIX_BP, PIN_RX_MIX_BP);
}
if (ctrl & SWITCHCTRL_HP) {
gpio_set(PORT_HP, PIN_HP);
gpio_clear(PORT_LP, PIN_LP);
} else {
gpio_clear(PORT_HP, PIN_HP);
gpio_set(PORT_LP, PIN_LP);
}
if (ctrl & SWITCHCTRL_AMP_BYPASS) {
gpio_set(PORT_AMP_BYPASS, PIN_AMP_BYPASS);
gpio_clear(PORT_TX_AMP, PIN_TX_AMP);
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
gpio_clear(PORT_RX_AMP, PIN_RX_AMP);
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
} else if (ctrl & SWITCHCTRL_TX) {
gpio_clear(PORT_AMP_BYPASS, PIN_AMP_BYPASS);
gpio_set(PORT_TX_AMP, PIN_TX_AMP);
gpio_clear(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
gpio_clear(PORT_RX_AMP, PIN_RX_AMP);
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
} else {
gpio_clear(PORT_AMP_BYPASS, PIN_AMP_BYPASS);
gpio_clear(PORT_TX_AMP, PIN_TX_AMP);
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
gpio_set(PORT_RX_AMP, PIN_RX_AMP);
gpio_clear(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
}
/*
* These normally shouldn't be set post-Jawbreaker, but they can be
* used to explicitly turn off power to the amplifiers while AMP_BYPASS
* is unset:
*/
if (ctrl & SWITCHCTRL_NO_TX_AMP_PWR)
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR)
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
}
#endif
static void switchctrl_set(const uint8_t gpo) {
#ifdef JAWBREAKER
rffc5071_set_gpo(gpo);
#elif HACKRF_ONE
switchctrl_set_hackrf_one(gpo);
#else
(void)gpo;
#endif
}
void rf_path_pin_setup() {
#ifdef HACKRF_ONE
/* Configure RF switch control signals */
scu_pinmux(SCU_HP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_LP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_TX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_NO_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_RX_MIX_BP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_TX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_MIX_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_NO_TX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_AMP_BYPASS, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_RX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_NO_RX_AMP_PWR, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
/* Configure RF power supply (VAA) switch */
scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
/* Configure RF switch control signals as outputs */
GPIO0_DIR |= PIN_AMP_BYPASS;
GPIO1_DIR |= (PIN_NO_MIX_BYPASS | PIN_RX_AMP | PIN_NO_RX_AMP_PWR);
GPIO2_DIR |= (PIN_HP | PIN_LP | PIN_TX_MIX_BP | PIN_RX_MIX_BP | PIN_TX_AMP);
GPIO3_DIR |= PIN_NO_TX_AMP_PWR;
GPIO5_DIR |= (PIN_TX | PIN_MIX_BYPASS | PIN_RX);
/*
* Safe (initial) switch settings turn off both amplifiers and enable both
* amp bypass and mixer bypass.
*/
switchctrl_set(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS);
/* Configure RF power supply (VAA) switch control signal as output */
GPIO_DIR(PORT_NO_VAA_ENABLE) |= PIN_NO_VAA_ENABLE;
/* Safe state: start with VAA turned off: */
disable_rf_power();
#endif
}
void rf_path_init(void) {
ssp1_set_mode_max5864();
max5864_shutdown();
ssp1_set_mode_max2837();
max2837_setup();
max2837_start();
rffc5071_setup();
switchctrl_set(switchctrl);
}
void rf_path_set_direction(const rf_path_direction_t direction) {
/* Turn off TX and RX amplifiers, then enable based on direction and bypass state. */
switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
switch(direction) {
case RF_PATH_DIRECTION_TX:
switchctrl |= SWITCHCTRL_TX;
if( (switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
/* TX amplifier is in path, be sure to enable TX amplifier. */
switchctrl &= ~SWITCHCTRL_NO_TX_AMP_PWR;
}
rffc5071_tx();
if( switchctrl & SWITCHCTRL_MIX_BYPASS ) {
rffc5071_disable();
} else {
rffc5071_enable();
}
ssp1_set_mode_max5864();
max5864_tx();
ssp1_set_mode_max2837();
max2837_tx();
sgpio_configure(SGPIO_DIRECTION_TX);
break;
case RF_PATH_DIRECTION_RX:
switchctrl &= ~SWITCHCTRL_TX;
if( (switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
/* RX amplifier is in path, be sure to enable RX amplifier. */
switchctrl &= ~SWITCHCTRL_NO_RX_AMP_PWR;
}
rffc5071_rx();
if( switchctrl & SWITCHCTRL_MIX_BYPASS ) {
rffc5071_disable();
} else {
rffc5071_enable();
}
ssp1_set_mode_max5864();
max5864_rx();
ssp1_set_mode_max2837();
max2837_rx();
sgpio_configure(SGPIO_DIRECTION_RX);
break;
case RF_PATH_DIRECTION_OFF:
default:
/* Set RF path to receive direction when "off" */
switchctrl &= ~SWITCHCTRL_TX;
rffc5071_disable();
ssp1_set_mode_max5864();
max5864_standby();
ssp1_set_mode_max2837();
max2837_set_mode(MAX2837_MODE_STANDBY);
sgpio_configure(SGPIO_DIRECTION_RX);
break;
}
switchctrl_set(switchctrl);
}
void rf_path_set_filter(const rf_path_filter_t filter) {
switch(filter) {
default:
case RF_PATH_FILTER_BYPASS:
switchctrl |= SWITCHCTRL_MIX_BYPASS;
rffc5071_disable();
break;
case RF_PATH_FILTER_LOW_PASS:
switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
rffc5071_enable();
break;
case RF_PATH_FILTER_HIGH_PASS:
switchctrl &= ~SWITCHCTRL_MIX_BYPASS;
switchctrl |= SWITCHCTRL_HP;
rffc5071_enable();
break;
}
switchctrl_set(switchctrl);
}
void rf_path_set_lna(const uint_fast8_t enable) {
if( enable ) {
if( switchctrl & SWITCHCTRL_TX ) {
/* AMP_BYPASS=0, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=0 */
switchctrl |= SWITCHCTRL_NO_RX_AMP_PWR;
switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR);
} else {
/* AMP_BYPASS=0, NO_RX_AMP_PWR=0, NO_TX_AMP_PWR=1 */
switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR;
switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_RX_AMP_PWR);
}
} else {
/* AMP_BYPASS=1, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=1 */
switchctrl |= SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
}
switchctrl_set(switchctrl);
}

49
firmware/common/rf_path.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __RFPATH_H__
#define __RFPATH_H__
#include <stdint.h>
void rf_path_pin_setup(void);
void rf_path_init(void);
typedef enum {
RF_PATH_DIRECTION_OFF,
RF_PATH_DIRECTION_RX,
RF_PATH_DIRECTION_TX,
} rf_path_direction_t;
void rf_path_set_direction(const rf_path_direction_t direction);
typedef enum {
RF_PATH_FILTER_BYPASS,
RF_PATH_FILTER_LOW_PASS,
RF_PATH_FILTER_HIGH_PASS,
} rf_path_filter_t;
void rf_path_set_filter(const rf_path_filter_t filter);
void rf_path_set_lna(const uint_fast8_t enable);
#endif/*__RFPATH_H__*/

View File

@ -145,11 +145,6 @@ void rffc5071_setup(void)
* not control pins. */
set_RFFC5071_SIPIN(1);
#ifdef JAWBREAKER
/* initial safe switch control settings */
rffc5071_set_gpo(SWITCHCTRL_SAFE);
#endif
/* GPOs are active at all times */
set_RFFC5071_GATE(1);
@ -367,60 +362,20 @@ void rffc5071_regs_commit(void)
}
}
void rffc5071_tx(uint8_t gpo) {
void rffc5071_tx(void) {
LOG("# rffc5071_tx\n");
set_RFFC5071_ENBL(0);
set_RFFC5071_FULLD(0);
set_RFFC5071_MODE(1); /* mixer 2 used for both RX and TX */
/* honor SWITCHCTRL_AMP_BYPASS and SWITCHCTRL_HP settings from caller */
gpo &= (SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
if ((gpo & SWITCHCTRL_AMP_BYPASS) == SWITCHCTRL_AMP_BYPASS)
gpo |= SWITCHCTRL_NO_TX_AMP_PWR;
gpo |= (SWITCHCTRL_TX | SWITCHCTRL_NO_RX_AMP_PWR);
#ifdef JAWBREAKER
rffc5071_set_gpo(gpo);
#elif HACKRF_ONE
switchctrl_set(gpo);
#else
(void)gpo;
#endif
rffc5071_regs_commit();
#if (defined JAWBREAKER || defined HACKRF_ONE)
/* honor SWITCHCTRL_MIX_BYPASS setting from caller */
if ((gpo & SWITCHCTRL_MIX_BYPASS) == SWITCHCTRL_MIX_BYPASS)
rffc5071_disable();
else
#endif
rffc5071_enable();
}
void rffc5071_rx(uint8_t gpo) {
void rffc5071_rx(void) {
LOG("# rfc5071_rx\n");
set_RFFC5071_ENBL(0);
set_RFFC5071_FULLD(0);
set_RFFC5071_MODE(1); /* mixer 2 used for both RX and TX */
/* honor SWITCHCTRL_AMP_BYPASS and SWITCHCTRL_HP settings from caller */
gpo &= (SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
if ((gpo & SWITCHCTRL_AMP_BYPASS) == SWITCHCTRL_AMP_BYPASS)
gpo |= SWITCHCTRL_NO_RX_AMP_PWR;
gpo |= SWITCHCTRL_NO_TX_AMP_PWR;
#ifdef JAWBREAKER
rffc5071_set_gpo(gpo);
#elif HACKRF_ONE
switchctrl_set(gpo);
#else
(void)gpo;
#endif
rffc5071_regs_commit();
#if (defined JAWBREAKER || defined HACKRF_ONE)
/* honor SWITCHCTRL_MIX_BYPASS setting from caller */
if ((gpo & SWITCHCTRL_MIX_BYPASS) == SWITCHCTRL_MIX_BYPASS)
rffc5071_disable();
else
#endif
rffc5071_enable();
}
/*

View File

@ -53,8 +53,8 @@ extern uint32_t rffc5071_set_frequency(uint16_t mhz);
/* Set up rx only, tx only, or full duplex. Chip should be disabled
* before _tx, _rx, or _rxtx are called. */
extern void rffc5071_tx(uint8_t);
extern void rffc5071_rx(uint8_t);
extern void rffc5071_tx(void);
extern void rffc5071_rx(void);
extern void rffc5071_rxtx(void);
extern void rffc5071_enable(void);
extern void rffc5071_disable(void);

View File

@ -20,11 +20,16 @@
* Boston, MA 02110-1301, USA.
*/
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/sgpio.h>
#include <hackrf_core.h>
#include <sgpio.h>
static bool sgpio_slice_mode_multislice = true;
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);
@ -39,9 +44,13 @@ void sgpio_configure_pin_functions() {
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);
scu_pinmux(SCU_PINMUX_SGPIO13, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[12] */
scu_pinmux(SCU_PINMUX_SGPIO14, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[13] */
scu_pinmux(SCU_PINMUX_SGPIO15, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[14] */
sgpio_cpld_stream_rx_set_decimation(0);
GPIO_DIR(GPIO5) |= GPIOPIN14 | GPIOPIN13 | GPIOPIN12;
}
@ -56,8 +65,6 @@ void sgpio_test_interface() {
// 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) =
@ -90,6 +97,11 @@ void sgpio_test_interface() {
}
}
void sgpio_set_slice_mode(
const bool multi_slice
) {
sgpio_slice_mode_multislice = multi_slice;
}
/*
SGPIO0 to 7 = DAC/ADC data bits 0 to 7 (Nota: DAC is 10bits but only bit9 to bit2 are used bit1 & 0 are forced to 0 by CPLD)
@ -104,17 +116,14 @@ void sgpio_test_interface() {
SGPIO11 Direction Output (1/High=TX mode LPC43xx=>CPLD=>DAC, 0/Low=RX mode LPC43xx<=CPLD<=ADC)
*/
void sgpio_configure(
const transceiver_mode_t transceiver_mode,
const bool multi_slice
const sgpio_direction_t direction
) {
// Disable all counters during configuration
SGPIO_CTRL_ENABLE = 0;
sgpio_configure_pin_functions();
// Set SGPIO output values.
const uint_fast8_t cpld_direction =
(transceiver_mode == TRANSCEIVER_MODE_TX) ? 1 : 0;
(direction == SGPIO_DIRECTION_TX) ? 1 : 0;
SGPIO_GPIO_OUTREG =
(cpld_direction << 11) /* 1=Output SGPIO11 High(TX mode), 0=Output SGPIO11 Low(RX mode)*/
| (1L << 10) // disable codec data stream during configuration (Output SGPIO10 High)
@ -122,11 +131,12 @@ void sgpio_configure(
// Enable SGPIO pin outputs.
const uint_fast16_t sgpio_gpio_data_direction =
(transceiver_mode == TRANSCEIVER_MODE_TX)
(direction == SGPIO_DIRECTION_TX)
? (0xFF << 0)
: (0x00 << 0);
SGPIO_GPIO_OENREG =
(1L << 11) // direction output SGPIO11 active
(1L << 14) // GPDMA burst request SGPIO14 active
| (1L << 11) // direction output SGPIO11 active
| (1L << 10) // disable output SGPIO10 active
| (0L << 9) // capture input SGPIO9 (output i is tri-stated)
| (0L << 8) // clock input SGPIO8 (output i is tri-stated)
@ -149,9 +159,13 @@ void sgpio_configure(
SGPIO_OUT_MUX_CFG_P_OE_CFG(0) /* 0x0 gpio_oe (state set by GPIO_OEREG) */
| SGPIO_OUT_MUX_CFG_P_OUT_CFG(4) /* 0x4=gpio_out (level set by GPIO_OUTREG) */
;
SGPIO_OUT_MUX_CFG(14) = // SGPIO14: Output: internal GPDMA burst request
SGPIO_OUT_MUX_CFG_P_OE_CFG(0) /* 0x4 dout_oem1 (1-bit mode) */
| SGPIO_OUT_MUX_CFG_P_OUT_CFG(0) /* 0x0 dout_doutm1 (1-bit mode) */
;
const uint_fast8_t output_multiplexing_mode =
multi_slice ? 11 : 9;
sgpio_slice_mode_multislice ? 11 : 9;
/* SGPIO0 to SGPIO7 */
for(uint_fast8_t i=0; i<8; i++) {
// SGPIO pin 0 outputs slice A bit "i".
@ -171,20 +185,21 @@ void sgpio_configure(
SGPIO_SLICE_F,
SGPIO_SLICE_L,
};
const uint_fast8_t slice_gpdma = SGPIO_SLICE_H;
const uint_fast8_t pos = multi_slice ? 0x1f : 0x03;
const bool single_slice = !multi_slice;
const uint_fast8_t slice_count = multi_slice ? 8 : 1;
const uint_fast8_t pos = sgpio_slice_mode_multislice ? 0x1f : 0x03;
const bool single_slice = !sgpio_slice_mode_multislice;
const uint_fast8_t slice_count = sgpio_slice_mode_multislice ? 8 : 1;
const uint_fast8_t clk_capture_mode = (direction == SGPIO_DIRECTION_TX) ? 0 : 1;
uint32_t slice_enable_mask = 0;
/* Configure Slice A, I, E, J, C, K, F, L (multi_slice mode) */
/* Configure Slice A, I, E, J, C, K, F, L (sgpio_slice_mode_multislice mode) */
for(uint_fast8_t i=0; i<slice_count; i++)
{
const uint_fast8_t slice_index = slice_indices[i];
const bool input_slice = (i == 0) && (transceiver_mode == TRANSCEIVER_MODE_RX); /* Only for slice0/A and RX mode set input_slice to 1 */
const bool input_slice = (i == 0) && (direction != SGPIO_DIRECTION_TX); /* Only for slice0/A and RX mode set input_slice to 1 */
const uint_fast8_t concat_order = (input_slice || single_slice) ? 0 : 3; /* 0x0=Self-loop(slice0/A RX mode), 0x3=8 slices */
const uint_fast8_t concat_enable = (input_slice || single_slice) ? 0 : 1; /* 0x0=External data pin(slice0/A RX mode), 0x1=Concatenate data */
const uint_fast8_t clk_capture_mode = (transceiver_mode == TRANSCEIVER_MODE_RX) ? 1 : 0;
SGPIO_MUX_CFG(slice_index) =
SGPIO_MUX_CFG_CONCAT_ORDER(concat_order)
@ -213,12 +228,46 @@ void sgpio_configure(
SGPIO_POS_POS_RESET(pos)
| SGPIO_POS_POS(pos)
;
SGPIO_REG(slice_index) = 0x80808080; // Primary output data register
SGPIO_REG_SS(slice_index) = 0x80808080; // Shadow output data register
SGPIO_REG(slice_index) = 0x00000000; // Primary output data register
SGPIO_REG_SS(slice_index) = 0x00000000; // Shadow output data register
slice_enable_mask |= (1 << slice_index);
}
if( sgpio_slice_mode_multislice == false ) {
SGPIO_MUX_CFG(slice_gpdma) =
SGPIO_MUX_CFG_CONCAT_ORDER(0) /* Self-loop */
| SGPIO_MUX_CFG_CONCAT_ENABLE(1)
| SGPIO_MUX_CFG_QUALIFIER_SLICE_MODE(0) /* Select qualifier slice A(0x0) */
| SGPIO_MUX_CFG_QUALIFIER_PIN_MODE(1) /* Select qualifier pin SGPIO9(0x1) */
| SGPIO_MUX_CFG_QUALIFIER_MODE(3) /* External SGPIO */
| SGPIO_MUX_CFG_CLK_SOURCE_SLICE_MODE(0) /* Select clock source slice D(0x0) */
| SGPIO_MUX_CFG_CLK_SOURCE_PIN_MODE(0) /* Source Clock Pin 0x0 = SGPIO8 */
| SGPIO_MUX_CFG_EXT_CLK_ENABLE(1) /* External clock signal(pin) selected */
;
SGPIO_SLICE_MUX_CFG(slice_gpdma) =
SGPIO_SLICE_MUX_CFG_INV_QUALIFIER(0) /* 0x0=Use normal qualifier. */
| SGPIO_SLICE_MUX_CFG_PARALLEL_MODE(0) /* 0x0=Shift 1 bit per clock. */
| SGPIO_SLICE_MUX_CFG_DATA_CAPTURE_MODE(0) /* 0x0=Detect rising edge. (Condition for input bit match interrupt) */
| SGPIO_SLICE_MUX_CFG_INV_OUT_CLK(0) /* 0x0=Normal clock. */
| SGPIO_SLICE_MUX_CFG_CLKGEN_MODE(1) /* 0x1=Use external clock from a pin or other slice */
| SGPIO_SLICE_MUX_CFG_CLK_CAPTURE_MODE(clk_capture_mode) /* 0x0=Use rising clock edge, 0x1=Use falling clock edge */
| SGPIO_SLICE_MUX_CFG_MATCH_MODE(0) /* 0x0=Do not match data */
;
SGPIO_PRESET(slice_gpdma) = 0; // External clock, don't care
SGPIO_COUNT(slice_gpdma) = 0; // External clock, don't care
SGPIO_POS(slice_gpdma) =
SGPIO_POS_POS_RESET(0x1f)
| SGPIO_POS_POS(0x1f)
;
SGPIO_REG(slice_gpdma) = 0x11111111; // Primary output data register, LSB -> out
SGPIO_REG_SS(slice_gpdma) = 0x11111111; // Shadow output data register, LSB -> out1
slice_enable_mask |= (1 << slice_gpdma);
}
// Start SGPIO operation by enabling slice clocks.
SGPIO_CTRL_ENABLE = slice_enable_mask;
}
@ -236,3 +285,17 @@ void sgpio_cpld_stream_disable() {
bool sgpio_cpld_stream_is_enabled() {
return (SGPIO_GPIO_OUTREG & (1L << 10)) == 0; /* SGPIO10 */
}
bool sgpio_cpld_stream_rx_set_decimation(const uint_fast8_t skip_n) {
/* CPLD interface is three bits, SGPIO[15:13]:
* 111: decimate by 1 (skip_n=0, skip no samples)
* 110: decimate by 2 (skip_n=1, skip every other sample)
* 101: decimate by 3 (skip_n=2, skip two of three samples)
* ...
* 000: decimate by 8 (skip_n=7, skip seven of eight samples)
*/
GPIO_SET(GPIO5) = GPIOPIN14 | GPIOPIN13 | GPIOPIN12;
GPIO_CLR(GPIO5) = (skip_n & 7) << 12;
return (skip_n < 8);
}

View File

@ -24,14 +24,23 @@
#include <hackrf_core.h>
typedef enum {
SGPIO_DIRECTION_RX,
SGPIO_DIRECTION_TX,
} sgpio_direction_t;
void sgpio_configure_pin_functions();
void sgpio_test_interface();
void sgpio_configure(
const transceiver_mode_t transceiver_mode,
void sgpio_set_slice_mode(
const bool multi_slice
);
void sgpio_configure(
const sgpio_direction_t direction
);
void sgpio_cpld_stream_enable();
void sgpio_cpld_stream_disable();
bool sgpio_cpld_stream_is_enabled();
bool sgpio_cpld_stream_rx_set_decimation(const uint_fast8_t skip_n);
#endif//__SGPIO_H__

142
firmware/common/sgpio_dma.c Normal file
View File

@ -0,0 +1,142 @@
/*
* Copyright 2013 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <sgpio_dma.h>
#include <libopencm3/lpc43xx/creg.h>
#include <libopencm3/lpc43xx/gpdma.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/sgpio.h>
#include <sgpio.h>
#include <gpdma.h>
void sgpio_dma_configure_lli(
gpdma_lli_t* const lli,
const size_t lli_count,
const bool direction_transmit,
void* const buffer,
const size_t transfer_bytes
) {
const size_t bytes_per_word = 4;
const size_t transfer_words = (transfer_bytes + bytes_per_word - 1) / bytes_per_word;
gpdma_lli_create_loop(lli, lli_count);
for(size_t i=0; i<lli_count; i++) {
void* const peripheral_address = (void*)&SGPIO_REG_SS(0);
void* const memory_address = buffer + (transfer_words * bytes_per_word * i);
const uint_fast8_t source_master = direction_transmit ? 1 : 0;
const uint_fast8_t destination_master = direction_transmit ? 0 : 1;
const uint_fast8_t lli_fetch_master = direction_transmit ? 0 : 1;
lli[i].csrcaddr = direction_transmit ? memory_address : peripheral_address;
lli[i].cdestaddr = direction_transmit ? peripheral_address : memory_address;
lli[i].clli = (lli[i].clli & ~GPDMA_CLLI_LM_MASK) | GPDMA_CLLI_LM(lli_fetch_master);
lli[i].ccontrol =
GPDMA_CCONTROL_TRANSFERSIZE(transfer_words) |
GPDMA_CCONTROL_SBSIZE(0) |
GPDMA_CCONTROL_DBSIZE(0) |
GPDMA_CCONTROL_SWIDTH(2) |
GPDMA_CCONTROL_DWIDTH(2) |
GPDMA_CCONTROL_S(source_master) |
GPDMA_CCONTROL_D(destination_master) |
GPDMA_CCONTROL_SI(direction_transmit ? 1 : 0) |
GPDMA_CCONTROL_DI(direction_transmit ? 0 : 1) |
GPDMA_CCONTROL_PROT1(0) |
GPDMA_CCONTROL_PROT2(0) |
GPDMA_CCONTROL_PROT3(0) |
GPDMA_CCONTROL_I(0)
;
}
}
static void sgpio_dma_enable(const uint_fast8_t channel, const gpdma_lli_t* const lli, const bool direction_transmit) {
gpdma_channel_disable(channel);
gpdma_channel_interrupt_tc_clear(channel);
gpdma_channel_interrupt_error_clear(channel);
GPDMA_CSRCADDR(channel) = (uint32_t)lli->csrcaddr;
GPDMA_CDESTADDR(channel) = (uint32_t)lli->cdestaddr;
GPDMA_CLLI(channel) = (uint32_t)lli->clli;
GPDMA_CCONTROL(channel) = lli->ccontrol;
/* 1: Memory -> Peripheral
* 2: Peripheral -> Memory */
const uint_fast8_t flowcntrl = direction_transmit ? 1 : 2;
GPDMA_CCONFIG(channel) =
GPDMA_CCONFIG_E(0) |
GPDMA_CCONFIG_SRCPERIPHERAL(0) |
GPDMA_CCONFIG_DESTPERIPHERAL(0) |
GPDMA_CCONFIG_FLOWCNTRL(flowcntrl) |
GPDMA_CCONFIG_IE(1) |
GPDMA_CCONFIG_ITC(1) |
GPDMA_CCONFIG_L(0) |
GPDMA_CCONFIG_H(0)
;
gpdma_channel_enable(channel);
}
void sgpio_dma_init() {
/* DMA peripheral/source 0, option 2 (SGPIO14) -- BREQ */
CREG_DMAMUX &= ~(CREG_DMAMUX_DMAMUXPER0_MASK);
CREG_DMAMUX |= CREG_DMAMUX_DMAMUXPER0(0x2);
// Disable sync, maybe it is causing max speed (10MT/sec) glitches?
//GPDMA_DMACSYNC = (1 << 0);
//GPDMA_SYNC = GPDMA_SYNC_DMACSYNC(0xFFFF); // TODO: Don't do this, I'm just going nuts here.
gpdma_controller_enable();
}
static const uint_fast8_t dma_channel_sgpio = 0;
void sgpio_dma_rx_start(const gpdma_lli_t* const start_lli) {
sgpio_dma_enable(dma_channel_sgpio, start_lli, false);
}
void sgpio_dma_tx_start(const gpdma_lli_t* const start_lli) {
sgpio_dma_enable(dma_channel_sgpio, start_lli, true);
}
void sgpio_dma_irq_tc_acknowledge() {
gpdma_channel_interrupt_tc_clear(dma_channel_sgpio);
}
void sgpio_dma_stop() {
gpdma_channel_disable(dma_channel_sgpio);
}
size_t sgpio_dma_current_transfer_index(
const gpdma_lli_t* const lli,
const size_t lli_count
) {
const uint32_t next_lli = GPDMA_CLLI(dma_channel_sgpio);
for(size_t i=0; i<lli_count; i++) {
if( lli[i].clli == next_lli ) {
return i;
}
}
return 0;
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2013 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SGPIO_DMA_H__
#define __SGPIO_DMA_H__
#include <stddef.h>
#include <libopencm3/lpc43xx/gpdma.h>
void sgpio_dma_configure_lli(
gpdma_lli_t* const lli,
const size_t lli_count,
const bool direction_transmit,
void* const buffer,
const size_t transfer_bytes
);
void sgpio_dma_init();
void sgpio_dma_rx_start(const gpdma_lli_t* const start_lli);
void sgpio_dma_tx_start(const gpdma_lli_t* const start_lli);
void sgpio_dma_irq_tc_acknowledge();
void sgpio_dma_stop();
size_t sgpio_dma_current_transfer_index(
const gpdma_lli_t* const lli,
const size_t lli_count
);
#endif/*__SGPIO_DMA_H__*/

View File

@ -237,16 +237,16 @@ void si5351c_configure_clock_control()
,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_6MA)
,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_4MA)
,SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE /*not connected, but: plla int mode*/
,SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE /* pllb int mode*/| SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_B) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA)
,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(SI5351C_CLK_PLL_SRC_A) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA)
};
si5351c_write(data, sizeof(data));
}
#endif
/* Enable CLK outputs 0, 1, 2, 4, 5, ~7 only. */
/* Enable CLK outputs 0, 1, 2, 4, 5, 7 only. */
void si5351c_enable_clock_outputs()
{
uint8_t data[] = { 3, 0xC8 };
uint8_t data[] = { 3, 0x48 };
si5351c_write(data, sizeof(data));
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include <streaming.h>
#include <libopencm3/lpc43xx/m4/nvic.h>
#include <libopencm3/lpc43xx/sgpio.h>
#include <sgpio.h>
void baseband_streaming_enable() {
nvic_set_priority(NVIC_SGPIO_IRQ, 0);
nvic_enable_irq(NVIC_SGPIO_IRQ);
SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A);
sgpio_cpld_stream_enable();
}
void baseband_streaming_disable() {
sgpio_cpld_stream_disable();
nvic_disable_irq(NVIC_SGPIO_IRQ);
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __STREAMING_H__
#define __STREAMING_H__
void baseband_streaming_enable();
void baseband_streaming_disable();
#endif/*__STREAMING_H__*/

126
firmware/common/tuning.c Normal file
View File

@ -0,0 +1,126 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "tuning.h"
#include <rffc5071.h>
#include <max2837.h>
#include "rf_path.h"
#define FREQ_ONE_MHZ (1000*1000)
#define MIN_LP_FREQ_MHZ (5)
#define MAX_LP_FREQ_MHZ (2300)
#define MIN_BYPASS_FREQ_MHZ (2300)
#define MAX_BYPASS_FREQ_MHZ (2700)
#define MIN_HP_FREQ_MHZ (2700)
#define MAX_HP_FREQ_MHZ (6800)
static uint32_t max2837_freq_nominal_hz=2560000000;
uint64_t freq_cache = 100000000;
/*
* Set freq/tuning between 5MHz to 6800 MHz (less than 16bits really used)
* hz between 0 to 999999 Hz (not checked)
* return false on error or true if success.
*/
bool set_freq(const uint64_t freq)
{
bool success;
uint32_t RFFC5071_freq_mhz;
uint32_t MAX2837_freq_hz;
uint32_t real_RFFC5071_freq_hz;
uint32_t tmp_hz;
const uint32_t freq_mhz = freq / 1000000;
const uint32_t freq_hz = freq % 1000000;
success = true;
const max2837_mode_t prior_max2837_mode = max2837_mode();
max2837_mode_standby();
if(freq_mhz >= MIN_LP_FREQ_MHZ)
{
if(freq_mhz < MAX_LP_FREQ_MHZ)
{
rf_path_set_filter(RF_PATH_FILTER_LOW_PASS);
RFFC5071_freq_mhz = (max2837_freq_nominal_hz / FREQ_ONE_MHZ) - freq_mhz;
/* Set Freq and read real freq */
real_RFFC5071_freq_hz = rffc5071_set_frequency(RFFC5071_freq_mhz);
if(real_RFFC5071_freq_hz < RFFC5071_freq_mhz * FREQ_ONE_MHZ)
{
tmp_hz = -(RFFC5071_freq_mhz * FREQ_ONE_MHZ - real_RFFC5071_freq_hz);
}else
{
tmp_hz = (real_RFFC5071_freq_hz - RFFC5071_freq_mhz * FREQ_ONE_MHZ);
}
MAX2837_freq_hz = max2837_freq_nominal_hz + tmp_hz + freq_hz;
max2837_set_frequency(MAX2837_freq_hz);
}else if( (freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ) )
{
rf_path_set_filter(RF_PATH_FILTER_BYPASS);
MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz;
/* RFFC5071_freq_mhz <= not used in Bypass mode */
max2837_set_frequency(MAX2837_freq_hz);
}else if( (freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz < MAX_HP_FREQ_MHZ) )
{
rf_path_set_filter(RF_PATH_FILTER_HIGH_PASS);
RFFC5071_freq_mhz = freq_mhz - (max2837_freq_nominal_hz / FREQ_ONE_MHZ);
/* Set Freq and read real freq */
real_RFFC5071_freq_hz = rffc5071_set_frequency(RFFC5071_freq_mhz);
if(real_RFFC5071_freq_hz < RFFC5071_freq_mhz * FREQ_ONE_MHZ)
{
tmp_hz = (RFFC5071_freq_mhz * FREQ_ONE_MHZ - real_RFFC5071_freq_hz);
}else
{
tmp_hz = -(real_RFFC5071_freq_hz - RFFC5071_freq_mhz * FREQ_ONE_MHZ);
}
MAX2837_freq_hz = max2837_freq_nominal_hz + tmp_hz + freq_hz;
max2837_set_frequency(MAX2837_freq_hz);
}else
{
/* Error freq_mhz too high */
success = false;
}
}else
{
/* Error freq_mhz too low */
success = false;
}
max2837_set_mode(prior_max2837_mode);
if( success ) {
freq_cache = freq;
}
return success;
}
bool set_freq_if(const uint32_t freq_if_hz) {
bool success = false;
if( (freq_if_hz >= MIN_BYPASS_FREQ_MHZ) && (freq_if_hz <= MAX_BYPASS_FREQ_MHZ) ) {
max2837_freq_nominal_hz = freq_if_hz;
success = set_freq(freq_cache);
}
return success;
}

32
firmware/common/tuning.h Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __TUNING_H__
#define __TUNING_H__
#include <stdint.h>
#include <stdbool.h>
bool set_freq(const uint64_t freq);
bool set_freq_if(const uint32_t freq_if_hz);
#endif/*__TUNING_H__*/

View File

@ -24,6 +24,7 @@
#include "usb.h"
#include "usb_type.h"
#include "usb_queue.h"
#include "usb_standard_request.h"
#include <libopencm3/lpc43xx/creg.h>
@ -34,10 +35,8 @@
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
@ -45,12 +44,6 @@ usb_queue_head_t* usb_queue_head(
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
) {
@ -98,25 +91,25 @@ static void usb_clear_all_pending_interrupts() {
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 );
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;
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 );
while( USB0_ENDPTFLUSH & mask );
}
static void usb_flush_primed_endpoints(const uint32_t mask) {
usb_wait_for_endpoint_priming_to_finish(mask);
usb_wait_for_endpoint_priming_to_finish(mask);
usb_flush_endpoints(mask);
usb_wait_for_endpoint_flushing_to_finish(mask);
usb_wait_for_endpoint_flushing_to_finish(mask);
}
static void usb_flush_all_primed_endpoints() {
@ -171,6 +164,7 @@ void usb_endpoint_disable(
} else {
USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_RXE);
}
usb_queue_flush_endpoint(endpoint);
usb_endpoint_clear_pending_interrupts(endpoint);
usb_endpoint_flush(endpoint);
}
@ -195,7 +189,7 @@ void usb_endpoint_prime(
USB0_ENDPTPRIME = USB0_ENDPTPRIME_PERB(1 << endpoint_number);
}
}
/*
static bool usb_endpoint_is_priming(
const usb_endpoint_t* const endpoint
) {
@ -206,11 +200,57 @@ static bool usb_endpoint_is_priming(
return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PERB(1 << endpoint_number);
}
}
*/
// Schedule an already filled-in transfer descriptor for execution on
// the given endpoint, waiting until the endpoint has finished.
void usb_endpoint_schedule_wait(
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) );
td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
usb_endpoint_prime(endpoint, td);
}
// Schedule an already filled-in transfer descriptor for execution on
// the given endpoint, appending to the end of the endpoint's queue if
// there are pending TDs. Note that this requires that one knows the
// tail of the endpoint's TD queue. Moreover, the user is responsible
// for setting the TERMINATE bit of next_dtd_pointer if needed.
void usb_endpoint_schedule_append(
const usb_endpoint_t* const endpoint,
usb_transfer_descriptor_t* const tail_td,
usb_transfer_descriptor_t* const new_td
) {
bool done;
tail_td->next_dtd_pointer = new_td;
if (usb_endpoint_is_priming(endpoint)) {
return;
}
do {
USB0_USBCMD_D |= USB0_USBCMD_D_ATDTW;
done = usb_endpoint_is_ready(endpoint);
} while (!(USB0_USBCMD_D & USB0_USBCMD_D_ATDTW));
USB0_USBCMD_D &= ~USB0_USBCMD_D_ATDTW;
if(!done) {
usb_endpoint_prime(endpoint, new_td);
}
}
void usb_endpoint_flush(
const usb_endpoint_t* const endpoint
) {
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
usb_queue_flush_endpoint(endpoint);
if( usb_endpoint_is_in(endpoint->address) ) {
usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FETB(1 << endpoint_number));
} else {
@ -510,48 +550,13 @@ void usb_endpoint_init(
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_t* const endpoint =
usb_endpoint_from_address(
usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i)
);

View File

@ -61,16 +61,6 @@ 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
);
@ -92,4 +82,15 @@ void usb_endpoint_prime(
usb_transfer_descriptor_t* const first_td
);
void usb_endpoint_schedule_wait(
const usb_endpoint_t* const endpoint,
usb_transfer_descriptor_t* const td
);
void usb_endpoint_schedule_append(
const usb_endpoint_t* const endpoint,
usb_transfer_descriptor_t* const tail_td,
usb_transfer_descriptor_t* const new_td
);
#endif//__USB_H__

227
firmware/common/usb_queue.c Normal file
View File

@ -0,0 +1,227 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 Ben Gamari
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <assert.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/sync.h>
#include "usb.h"
#include "usb_queue.h"
usb_queue_t* endpoint_queues[12] = {};
#define USB_ENDPOINT_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1))
static usb_queue_t* endpoint_queue(
const usb_endpoint_t* const endpoint
) {
uint32_t index = USB_ENDPOINT_INDEX(endpoint->address);
if (endpoint_queues[index] == NULL) while (1);
return endpoint_queues[index];
}
void usb_queue_init(
usb_queue_t* const queue
) {
uint32_t index = USB_ENDPOINT_INDEX(queue->endpoint->address);
if (endpoint_queues[index] != NULL) while (1);
endpoint_queues[index] = queue;
usb_transfer_t* t = queue->free_transfers;
for (unsigned int i=0; i < queue->pool_size - 1; i++, t++) {
t->next = t+1;
t->queue = queue;
}
t->next = NULL;
t->queue = queue;
}
/* Allocate a transfer */
static usb_transfer_t* allocate_transfer(
usb_queue_t* const queue
) {
bool aborted;
usb_transfer_t* transfer;
if (queue->free_transfers == NULL)
return NULL;
do {
transfer = (void *) __ldrex((uint32_t *) &queue->free_transfers);
aborted = __strex((uint32_t) transfer->next, (uint32_t *) &queue->free_transfers);
} while (aborted);
transfer->next = NULL;
return transfer;
}
/* Place a transfer in the free list */
static void free_transfer(usb_transfer_t* const transfer)
{
usb_queue_t* const queue = transfer->queue;
bool aborted;
do {
transfer->next = (void *) __ldrex((uint32_t *) &queue->free_transfers);
aborted = __strex((uint32_t) transfer, (uint32_t *) &queue->free_transfers);
} while (aborted);
}
/* Add a transfer to the end of an endpoint's queue. Returns the old
* tail or NULL is the queue was empty
*/
static usb_transfer_t* endpoint_queue_transfer(
usb_transfer_t* const transfer
) {
usb_queue_t* const queue = transfer->queue;
transfer->next = NULL;
if (queue->active != NULL) {
usb_transfer_t* t = queue->active;
while (t->next != NULL) t = t->next;
t->next = transfer;
return t;
} else {
queue->active = transfer;
return NULL;
}
}
static void usb_queue_flush_queue(usb_queue_t* const queue)
{
cm_disable_interrupts();
while (queue->active) {
usb_transfer_t* transfer = queue->active;
queue->active = transfer->next;
free_transfer(transfer);
}
cm_enable_interrupts();
}
void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint)
{
usb_queue_flush_queue(endpoint_queue(endpoint));
}
int usb_transfer_schedule(
const usb_endpoint_t* const endpoint,
void* const data,
const uint32_t maximum_length,
const transfer_completion_cb completion_cb,
void* const user_data
) {
usb_queue_t* const queue = endpoint_queue(endpoint);
usb_transfer_t* const transfer = allocate_transfer(queue);
if (transfer == NULL) return -1;
usb_transfer_descriptor_t* const td = &transfer->td;
// Configure the transfer descriptor
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;
// Fill in transfer fields
transfer->maximum_length = maximum_length;
transfer->completion_cb = completion_cb;
transfer->user_data = user_data;
cm_disable_interrupts();
usb_transfer_t* tail = endpoint_queue_transfer(transfer);
if (tail == NULL) {
// The queue is currently empty, we need to re-prime
usb_endpoint_schedule_wait(queue->endpoint, &transfer->td);
} else {
// The queue is currently running, try to append
usb_endpoint_schedule_append(queue->endpoint, &tail->td, &transfer->td);
}
cm_enable_interrupts();
return 0;
}
int usb_transfer_schedule_block(
const usb_endpoint_t* const endpoint,
void* const data,
const uint32_t maximum_length,
const transfer_completion_cb completion_cb,
void* const user_data
) {
int ret;
do {
ret = usb_transfer_schedule(endpoint, data, maximum_length,
completion_cb, user_data);
} while (ret == -1);
return 0;
}
int usb_transfer_schedule_ack(
const usb_endpoint_t* const endpoint
) {
return usb_transfer_schedule_block(endpoint, 0, 0, NULL, NULL);
}
/* Called when an endpoint might have completed a transfer */
void usb_queue_transfer_complete(usb_endpoint_t* const endpoint)
{
usb_queue_t* const queue = endpoint_queue(endpoint);
if (queue == NULL) while(1); // Uh oh
usb_transfer_t* transfer = queue->active;
while (transfer != NULL) {
uint8_t status = transfer->td.total_bytes;
// Check for failures
if ( status & USB_TD_DTD_TOKEN_STATUS_HALTED
|| status & USB_TD_DTD_TOKEN_STATUS_BUFFER_ERROR
|| status & USB_TD_DTD_TOKEN_STATUS_TRANSACTION_ERROR) {
// TODO: Uh oh, do something useful here
while (1);
}
// Still not finished
if (status & USB_TD_DTD_TOKEN_STATUS_ACTIVE)
break;
// Advance the head. We need to do this before invoking the completion
// callback as it might attempt to schedule a new transfer
queue->active = transfer->next;
usb_transfer_t* next = transfer->next;
// Invoke completion callback
unsigned int total_bytes = (transfer->td.total_bytes & USB_TD_DTD_TOKEN_TOTAL_BYTES_MASK) >> USB_TD_DTD_TOKEN_TOTAL_BYTES_SHIFT;
unsigned int transferred = transfer->maximum_length - total_bytes;
if (transfer->completion_cb)
transfer->completion_cb(transfer->user_data, transferred);
// Advance head and free transfer
free_transfer(transfer);
transfer = next;
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 Ben Gamari
*
* 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_QUEUE_H__
#define __USB_QUEUE_H__
#include <libopencm3/lpc43xx/usb.h>
#include "usb_type.h"
typedef struct _usb_transfer_t usb_transfer_t;
typedef struct _usb_queue_t usb_queue_t;
typedef void (*transfer_completion_cb)(void*, unsigned int);
// This is an opaque datatype. Thou shall not touch these members.
struct _usb_transfer_t {
struct _usb_transfer_t* next;
usb_transfer_descriptor_t td ATTR_ALIGNED(64);
unsigned int maximum_length;
struct _usb_queue_t* queue;
transfer_completion_cb completion_cb;
void* user_data;
};
// This is an opaque datatype. Thou shall not touch these members.
struct _usb_queue_t {
struct usb_endpoint_t* endpoint;
const unsigned int pool_size;
usb_transfer_t* volatile free_transfers;
usb_transfer_t* volatile active;
};
#define USB_DECLARE_QUEUE(endpoint_name) \
struct _usb_queue_t endpoint_name##_queue;
#define USB_DEFINE_QUEUE(endpoint_name, _pool_size) \
struct _usb_transfer_t endpoint_name##_transfers[_pool_size]; \
struct _usb_queue_t endpoint_name##_queue = { \
.endpoint = &endpoint_name, \
.free_transfers = endpoint_name##_transfers, \
.pool_size = _pool_size \
};
void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint);
int usb_transfer_schedule(
const usb_endpoint_t* const endpoint,
void* const data,
const uint32_t maximum_length,
const transfer_completion_cb completion_cb,
void* const user_data
);
int usb_transfer_schedule_block(
const usb_endpoint_t* const endpoint,
void* const data,
const uint32_t maximum_length,
const transfer_completion_cb completion_cb,
void* const user_data
);
int usb_transfer_schedule_ack(
const usb_endpoint_t* const endpoint
);
void usb_queue_init(
usb_queue_t* const queue
);
void usb_queue_transfer_complete(
usb_endpoint_t* const endpoint
);
#endif//__USB_QUEUE_H__

View File

@ -21,6 +21,7 @@
#include "usb.h"
#include "usb_request.h"
#include "usb_queue.h"
#include <stdbool.h>
@ -75,6 +76,7 @@ void usb_control_out_complete(
} else {
usb_request(endpoint, USB_TRANSFER_STAGE_DATA);
}
usb_queue_transfer_complete(endpoint);
}
void usb_control_in_complete(
@ -87,5 +89,6 @@ void usb_control_in_complete(
} else {
usb_request(endpoint, USB_TRANSFER_STAGE_STATUS);
}
usb_queue_transfer_complete(endpoint);
}

View File

@ -26,7 +26,7 @@
#include "usb.h"
#include "usb_type.h"
#include "usb_descriptor.h"
#include "usb_queue.h"
const uint8_t* usb_endpoint_descriptor(
const usb_endpoint_t* const endpoint
@ -99,27 +99,31 @@ bool usb_set_configuration(
if( new_configuration != device->configuration ) {
// Configuration changed.
device->configuration = new_configuration;
if (usb_configuration_changed_cb)
usb_configuration_changed_cb(device);
}
if (usb_configuration_changed_cb)
usb_configuration_changed_cb(device);
return true;
}
static usb_request_status_t usb_send_descriptor(
usb_endpoint_t* const endpoint,
uint8_t* const descriptor_data
const uint8_t* const descriptor_data
) {
const uint32_t setup_length = endpoint->setup.length;
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(
// We cast the const away but this shouldn't be a problem as this is a write transfer
usb_transfer_schedule_block(
endpoint->in,
descriptor_data,
(setup_length > descriptor_length) ? descriptor_length : setup_length
(uint8_t* const) descriptor_data,
(setup_length > descriptor_length) ? descriptor_length : setup_length,
NULL, NULL
);
usb_endpoint_schedule_ack(endpoint->out);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
@ -127,39 +131,58 @@ static usb_request_status_t 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++ ) {
for( uint_fast8_t i=0; endpoint->device->descriptor_strings[i] != 0; i++ ) {
if( i == index ) {
return usb_send_descriptor(endpoint, usb_descriptor_strings[i]);
return usb_send_descriptor(endpoint, endpoint->device->descriptor_strings[i]);
}
}
return USB_REQUEST_STATUS_STALL;
}
static usb_request_status_t usb_send_descriptor_config(
usb_endpoint_t* const endpoint,
usb_speed_t speed,
const uint8_t config_num
) {
usb_configuration_t** config = *(endpoint->device->configurations);
unsigned int i = 0;
for( ; *config != NULL; config++ ) {
if( (*config)->speed == speed) {
if (i == config_num) {
return usb_send_descriptor(endpoint, (*config)->descriptor);
} else {
i++;
}
}
}
return USB_REQUEST_STATUS_STALL;
}
static usb_request_status_t usb_standard_request_get_descriptor_setup(
usb_endpoint_t* const endpoint
) {
switch( endpoint->setup.value_h ) {
case USB_DESCRIPTOR_TYPE_DEVICE:
return usb_send_descriptor(endpoint, usb_descriptor_device);
return usb_send_descriptor(endpoint, endpoint->device->descriptor);
case USB_DESCRIPTOR_TYPE_CONFIGURATION:
// TODO: Duplicated code. Refactor.
if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) {
return usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed);
return usb_send_descriptor_config(endpoint, USB_SPEED_HIGH, endpoint->setup.value_l);
} else {
return usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed);
return usb_send_descriptor_config(endpoint, USB_SPEED_FULL, endpoint->setup.value_l);
}
case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
return usb_send_descriptor(endpoint, usb_descriptor_device_qualifier);
return usb_send_descriptor(endpoint, endpoint->device->qualifier_descriptor);
case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION:
// TODO: Duplicated code. Refactor.
if( usb_speed(endpoint->device) == USB_SPEED_HIGH ) {
return usb_send_descriptor(endpoint, usb_descriptor_configuration_full_speed);
return usb_send_descriptor_config(endpoint, USB_SPEED_FULL, endpoint->setup.value_l);
} else {
return usb_send_descriptor(endpoint, usb_descriptor_configuration_high_speed);
return usb_send_descriptor_config(endpoint, USB_SPEED_HIGH, endpoint->setup.value_l);
}
case USB_DESCRIPTOR_TYPE_STRING:
@ -195,7 +218,7 @@ static usb_request_status_t usb_standard_request_set_address_setup(
usb_endpoint_t* const endpoint
) {
usb_set_address_deferred(endpoint->device, endpoint->setup.value_l);
usb_endpoint_schedule_ack(endpoint->in);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
}
@ -231,7 +254,7 @@ static usb_request_status_t usb_standard_request_set_configuration_setup(
// TODO: Should this be done immediately?
usb_set_address_immediate(endpoint->device, 0);
}
usb_endpoint_schedule_ack(endpoint->in);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
} else {
return USB_REQUEST_STATUS_STALL;
@ -265,8 +288,8 @@ static usb_request_status_t usb_standard_request_get_configuration_setup(
if( endpoint->device->configuration ) {
endpoint->buffer[0] = endpoint->device->configuration->number;
}
usb_endpoint_schedule(endpoint->in, &endpoint->buffer, 1);
usb_endpoint_schedule_ack(endpoint->out);
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
} else {
return USB_REQUEST_STATUS_STALL;

View File

@ -123,6 +123,8 @@ typedef struct {
typedef struct {
const uint8_t* const descriptor;
uint8_t** descriptor_strings;
const uint8_t* const qualifier_descriptor;
usb_configuration_t* (*configurations)[];
const usb_configuration_t* configuration;
} usb_device_t;

View File

@ -10,18 +10,11 @@
/* Add print in setPort for xapp058_example.exe.*/
/*******************************************************/
#include "ports.h"
/*#include "prgispx.h"*/
//#include "stdio.h"
#include "hackrf_core.h"
#include "cpld_jtag.h"
#include <libopencm3/lpc43xx/gpio.h>
//extern FILE *in;
//static int g_iTCK = 0; /* For xapp058_example .exe */
//static int g_iTMS = 0; /* For xapp058_example .exe */
//static int g_iTDI = 0; /* For xapp058_example .exe */
void delay_jtag(uint32_t duration)
{
#define DIVISOR (1024)
@ -43,94 +36,10 @@ void delay_jtag(uint32_t duration)
__asm__("nop");
}
#ifdef WIN95PP
#include "conio.h"
#define DATA_OFFSET (unsigned short) 0
#define STATUS_OFFSET (unsigned short) 1
#define CONTROL_OFFSET (unsigned short) 2
typedef union outPortUnion {
unsigned char value;
struct opBitsStr {
unsigned char tdi:1;
unsigned char tck:1;
unsigned char tms:1;
unsigned char zero:1;
unsigned char one:1;
unsigned char bit5:1;
unsigned char bit6:1;
unsigned char bit7:1;
} bits;
} outPortType;
typedef union inPortUnion {
unsigned char value;
struct ipBitsStr {
unsigned char bit0:1;
unsigned char bit1:1;
unsigned char bit2:1;
unsigned char bit3:1;
unsigned char tdo:1;
unsigned char bit5:1;
unsigned char bit6:1;
unsigned char bit7:1;
} bits;
} inPortType;
static inPortType in_word;
static outPortType out_word;
static unsigned short base_port = 0x378;
static int once = 0;
#endif
/*BYTE *xsvf_data=0;*/
/* setPort: Implement to set the named JTAG signal (p) to the new value (v).*/
/* if in debugging mode, then just set the variables */
void setPort(short p,short val)
{
#ifdef WIN95PP
/* Old Win95 example that is similar to a GPIO register implementation.
The old Win95 example maps individual bits of the
8-bit register (out_word) to the JTAG signals: TCK, TMS, TDI.
*/
/* Initialize static out_word register bits just once */
if (once == 0) {
out_word.bits.one = 1;
out_word.bits.zero = 0;
once = 1;
}
/* Update the local out_word copy of the JTAG signal to the new value. */
if (p==TMS)
out_word.bits.tms = (unsigned char) val;
if (p==TDI)
out_word.bits.tdi = (unsigned char) val;
if (p==TCK) {
out_word.bits.tck = (unsigned char) val;
(void) _outp( (unsigned short) (base_port + 0), out_word.value );
/* To save HW write cycles, this example only writes the local copy
of the JTAG signal values to the HW register when TCK changes. */
}
#endif
/* Printing code for the xapp058_example.exe. You must set the specified
JTAG signal (p) to the new value (v). See the above, old Win95 code
as an implementation example. */
/*
if (p==TMS)
g_iTMS = val;
if (p==TDI)
g_iTDI = val;
if (p==TCK) {
g_iTCK = val;
printf( "TCK = %d; TMS = %d; TDI = %d\n", g_iTCK, g_iTMS, g_iTDI );
}
*/
if (p==TMS) {
if (val)
gpio_set(PORT_CPLD_TMS, PIN_CPLD_TMS);
@ -167,9 +76,6 @@ void pulseClock()
/* read in a byte of data from the prom */
void readByte(unsigned char *data)
{
/* pretend reading using a file */
//*data = (unsigned char)fgetc( in );
/**data=*xsvf_data++;*/
*data = cpld_jtag_get_next_byte();
}
@ -177,20 +83,6 @@ void readByte(unsigned char *data)
/* read the TDO bit from port */
unsigned char readTDOBit()
{
#ifdef WIN95PP
/* Old Win95 example that is similar to a GPIO register implementation.
The old Win95 reads the hardware input register and extracts the TDO
value from the bit within the register that is assigned to the
physical JTAG TDO signal.
*/
in_word.value = (unsigned char) _inp( (unsigned short) (base_port + STATUS_OFFSET) );
if (in_word.bits.tdo == 0x1) {
return( (unsigned char) 1 );
}
#endif
/* You must return the current value of the JTAG TDO signal. */
//return( (unsigned char) 0 );
delay_jtag(2000);
return CPLD_TDO_STATE;
}
@ -218,39 +110,4 @@ void waitTime(long microsec)
{
pulseClock();
}
#if 0
/* Alternate implementation */
/* For systems with TCK rates << 1 MHz; Consider this implementation. */
/* This implementation does not work with Spartan-3AN or indirect flash
programming. */
if ( microsec >= 50L )
{
/* Make sure TCK is low during wait for XC18V00/XCFxxS */
/* Or, a running TCK implementation as shown above is an OK alternate */
setPort( TCK, 0 );
/* Use Windows Sleep(). Round up to the nearest millisec */
_sleep( ( microsec + 999L ) / 1000L );
}
else /* Satisfy FPGA JTAG configuration, startup TCK cycles */
{
for ( i = 0; i < microsec; ++i )
{
pulseClock();
}
}
#endif
#if 0
/* Alternate implementation */
/* This implementation is valid for only XC9500/XL/XV, CoolRunner/II CPLDs,
XC18V00 PROMs, or Platform Flash XCFxxS/XCFxxP PROMs.
This implementation does not work with FPGAs JTAG configuration. */
/* Make sure TCK is low during wait for XC18V00/XCFxxS PROMs */
/* Or, a running TCK implementation as shown above is an OK alternate */
setPort( TCK, 0 );
/* Use Windows Sleep(). Round up to the nearest millisec */
_sleep( ( microsec + 999L ) / 1000L );
#endif
}

View File

@ -22,6 +22,25 @@ To program the SVF file into the CPLD:
required, and the "program" script below expects it to be at the relative
path "bsdl/xc2c/xc2c64.bsd".
Generate an XSVF
================
After generating a programming file:
* In the ISE Project Navigator, "Processes: top - Behavioral" pane, double-click "Configure Target Device".
* Click "OK" to open iMPACT.
* Ctrl-N to create a "New Project".
* "Yes" to automatically create and save a project file.
* Select "Prepare a Boundary-Scan File", choose "XSVF".
* Select file name "default.xsvf".
* Click "OK" to start adding devices.
* Assign new configuration file: "top.jed".
* Right-click the "xc2c64a top.jed" icon and select "Erase". Accept defaults.
* Right-click the "xc2c64a top.jed" icon and select "Program".
* Right-click the "xc2c64a top.jed" icon and select "Verify".
* Choose menu "Output" -> "XSVF File" -> "Stop Writing to XSVF File".
* Close iMPACT.
To Program
==========

File diff suppressed because it is too large Load Diff

BIN
firmware/cpld/sgpio_if/default.xsvf Executable file → Normal file

Binary file not shown.

View File

@ -9,10 +9,10 @@
<!-- along with the project source files, is sufficient to open and -->
<!-- implement in ISE Project Navigator. -->
<!-- -->
<!-- Copyright (c) 1995-2012 Xilinx, Inc. All rights reserved. -->
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
</header>
<version xil_pn:ise_version="14.1" xil_pn:schema_version="2"/>
<version xil_pn:ise_version="14.6" xil_pn:schema_version="2"/>
<files>
<file xil_pn:name="top.vhd" xil_pn:type="FILE_VHDL">

File diff suppressed because it is too large Load Diff

View File

@ -1,126 +1,67 @@
#
# 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.
# 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.
NET "CODEC_CLK" LOC="23" |IOSTANDARD=LVCMOS33;
NET "CODEC_CLK" LOC="23" |IOSTANDARD=LVCMOS33 | TNM=adc_data;
NET "CODEC_X2_CLK" LOC="27" |IOSTANDARD=LVCMOS33;
#NET "GCLK0" LOC="22" |IOSTANDARD=LVCMOS33;
NET "CODEC_X2_CLK" TNM_NET = CODEC_X2_CLK;
TIMESPEC TS_codec_x2_data = PERIOD "CODEC_X2_CLK" 50 ns;
TIMESPEC TS_codec_x2_data = PERIOD "CODEC_X2_CLK" 25 ns;
NET "DA<7>" LOC="35" |IOSTANDARD=LVCMOS33;
NET "DA<6>" LOC="36" |IOSTANDARD=LVCMOS33;
NET "DA<5>" LOC="37" |IOSTANDARD=LVCMOS33;
NET "DA<4>" LOC="39" |IOSTANDARD=LVCMOS33;
NET "DA<3>" LOC="40" |IOSTANDARD=LVCMOS33;
NET "DA<2>" LOC="41" |IOSTANDARD=LVCMOS33;
NET "DA<1>" LOC="42" |IOSTANDARD=LVCMOS33;
NET "DA<0>" LOC="43" |IOSTANDARD=LVCMOS33;
NET "DA<7>" LOC="35" |IOSTANDARD=LVCMOS33 | TNM=adc_data;
NET "DA<6>" LOC="36" |IOSTANDARD=LVCMOS33 | TNM=adc_data;
NET "DA<5>" LOC="37" |IOSTANDARD=LVCMOS33 | TNM=adc_data;
NET "DA<4>" LOC="39" |IOSTANDARD=LVCMOS33 | TNM=adc_data;
NET "DA<3>" LOC="40" |IOSTANDARD=LVCMOS33 | TNM=adc_data;
NET "DA<2>" LOC="41" |IOSTANDARD=LVCMOS33 | TNM=adc_data;
NET "DA<1>" LOC="42" |IOSTANDARD=LVCMOS33 | TNM=adc_data;
NET "DA<0>" LOC="43" |IOSTANDARD=LVCMOS33 | TNM=adc_data;
NET "DD<9>" LOC="17" |IOSTANDARD=LVCMOS33;
NET "DD<8>" LOC="18" |IOSTANDARD=LVCMOS33;
NET "DD<7>" LOC="19" |IOSTANDARD=LVCMOS33;
NET "DD<6>" LOC="24" |IOSTANDARD=LVCMOS33;
NET "DD<5>" LOC="28" |IOSTANDARD=LVCMOS33;
NET "DD<4>" LOC="29" |IOSTANDARD=LVCMOS33;
NET "DD<3>" LOC="30" |IOSTANDARD=LVCMOS33;
NET "DD<2>" LOC="32" |IOSTANDARD=LVCMOS33;
NET "DD<1>" LOC="33" |IOSTANDARD=LVCMOS33;
NET "DD<0>" LOC="34" |IOSTANDARD=LVCMOS33;
NET "DD<9>" LOC="17" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "DD<8>" LOC="18" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "DD<7>" LOC="19" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "DD<6>" LOC="24" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "DD<5>" LOC="28" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "DD<4>" LOC="29" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "DD<3>" LOC="30" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "DD<2>" LOC="32" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "DD<1>" LOC="33" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "DD<0>" LOC="34" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=dac_data;
NET "B1AUX<16>" LOC="60" |IOSTANDARD=LVCMOS33;
NET "B1AUX<15>" LOC="58" |IOSTANDARD=LVCMOS33;
NET "B1AUX<14>" LOC="56" |IOSTANDARD=LVCMOS33;
NET "B1AUX<13>" LOC="55" |IOSTANDARD=LVCMOS33;
NET "B1AUX<12>" LOC="53" |IOSTANDARD=LVCMOS33;
NET "B1AUX<11>" LOC="52" |IOSTANDARD=LVCMOS33;
NET "B1AUX<10>" LOC="50" |IOSTANDARD=LVCMOS33;
NET "B1AUX<9>" LOC="49" |IOSTANDARD=LVCMOS33;
NET "HOST_DIRECTION" LOC="71" |IOSTANDARD=LVCMOS33 | SLEW=SLOW;
NET "HOST_DISABLE" LOC="76" |IOSTANDARD=LVCMOS33 | SLEW=SLOW;
NET "HOST_CAPTURE" LOC="91" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=to_host;
NET "HOST_DATA<7>" LOC="77" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=to_host;
NET "HOST_DATA<6>" LOC="61" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=to_host;
NET "HOST_DATA<5>" LOC="64" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=to_host;
NET "HOST_DATA<4>" LOC="67" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=to_host;
NET "HOST_DATA<3>" LOC="72" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=to_host;
NET "HOST_DATA<2>" LOC="74" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=to_host;
NET "HOST_DATA<1>" LOC="79" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=to_host;
NET "HOST_DATA<0>" LOC="89" |IOSTANDARD=LVCMOS33 | SLEW=SLOW | TNM=to_host;
NET "HOST_DECIM_SEL<2>" LOC="78" |IOSTANDARD=LVCMOS33;
NET "HOST_DECIM_SEL<1>" LOC="81" |IOSTANDARD=LVCMOS33;
NET "HOST_DECIM_SEL<0>" LOC="90" |IOSTANDARD=LVCMOS33;
#NET "SGPIO<15>" LOC="78" |IOSTANDARD=LVCMOS33;
#NET "SGPIO<14>" LOC="81" |IOSTANDARD=LVCMOS33;
#NET "SGPIO<13>" LOC="90" |IOSTANDARD=LVCMOS33;
#NET "SGPIO<12>" LOC="70" |IOSTANDARD=LVCMOS33;
NET "HOST_DIRECTION" LOC="71" |IOSTANDARD=LVCMOS33;
NET "HOST_DISABLE" LOC="76" |IOSTANDARD=LVCMOS33;
NET "HOST_CAPTURE" LOC="91" |IOSTANDARD=LVCMOS33;
#NET "HOST_CLK" LOC="68" |IOSTANDARD=LVCMOS33;
NET "HOST_DATA<7>" LOC="77" |IOSTANDARD=LVCMOS33;
NET "HOST_DATA<6>" LOC="61" |IOSTANDARD=LVCMOS33;
NET "HOST_DATA<5>" LOC="64" |IOSTANDARD=LVCMOS33;
NET "HOST_DATA<4>" LOC="67" |IOSTANDARD=LVCMOS33;
NET "HOST_DATA<3>" LOC="72" |IOSTANDARD=LVCMOS33;
NET "HOST_DATA<2>" LOC="74" |IOSTANDARD=LVCMOS33;
NET "HOST_DATA<1>" LOC="79" |IOSTANDARD=LVCMOS33;
NET "HOST_DATA<0>" LOC="89" |IOSTANDARD=LVCMOS33;
TIMEGRP "adc_data" OFFSET = IN 16 ns BEFORE "CODEC_X2_CLK";
NET "B2AUX<16>" LOC="92" |IOSTANDARD=LVCMOS33;
NET "B2AUX<15>" LOC="94" |IOSTANDARD=LVCMOS33;
NET "B2AUX<14>" LOC="97" |IOSTANDARD=LVCMOS33;
NET "B2AUX<13>" LOC="99" |IOSTANDARD=LVCMOS33;
NET "B2AUX<12>" LOC="1" |IOSTANDARD=LVCMOS33;
NET "B2AUX<11>" LOC="2" |IOSTANDARD=LVCMOS33;
NET "B2AUX<10>" LOC="3" |IOSTANDARD=LVCMOS33;
NET "B2AUX<9>" LOC="4" |IOSTANDARD=LVCMOS33;
NET "B2AUX<8>" LOC="6" |IOSTANDARD=LVCMOS33;
NET "B2AUX<7>" LOC="7" |IOSTANDARD=LVCMOS33;
NET "B2AUX<6>" LOC="8" |IOSTANDARD=LVCMOS33;
NET "B2AUX<5>" LOC="9" |IOSTANDARD=LVCMOS33;
NET "B2AUX<4>" LOC="10" |IOSTANDARD=LVCMOS33;
NET "B2AUX<3>" LOC="11" |IOSTANDARD=LVCMOS33;
NET "B2AUX<2>" LOC="12" |IOSTANDARD=LVCMOS33;
NET "B2AUX<1>" LOC="13" |IOSTANDARD=LVCMOS33;
TIMEGRP "dac_data" OFFSET = OUT 15 ns AFTER "CODEC_X2_CLK";
INST "DA<0>" TNM=adc_data;
INST "DA<1>" TNM=adc_data;
INST "DA<2>" TNM=adc_data;
INST "DA<3>" TNM=adc_data;
INST "DA<4>" TNM=adc_data;
INST "DA<5>" TNM=adc_data;
INST "DA<6>" TNM=adc_data;
INST "DA<7>" TNM=adc_data;
TIMESPEC "TS_adc_data" = FROM "adc_data" TO "CODEC_X2_CLK" 16 ns;
INST "DD<0>" TNM=dac_data;
INST "DD<1>" TNM=dac_data;
INST "DD<2>" TNM=dac_data;
INST "DD<3>" TNM=dac_data;
INST "DD<4>" TNM=dac_data;
INST "DD<5>" TNM=dac_data;
INST "DD<6>" TNM=dac_data;
INST "DD<7>" TNM=dac_data;
INST "DD<8>" TNM=dac_data;
INST "DD<9>" TNM=dac_data;
TIMESPEC "TS_dac_data" = FROM "CODEC_X2_CLK" TO "dac_data" 15 ns;
INST "HOST_DATA<7>" TNM=to_host;
INST "HOST_DATA<6>" TNM=to_host;
INST "HOST_DATA<5>" TNM=to_host;
INST "HOST_DATA<4>" TNM=to_host;
INST "HOST_DATA<3>" TNM=to_host;
INST "HOST_DATA<2>" TNM=to_host;
INST "HOST_DATA<1>" TNM=to_host;
INST "HOST_DATA<0>" TNM=to_host;
INST "HOST_CAPTURE" TNM=to_host;
#TIMESPEC "TS_to_host" = FROM "to_host" TO "HOST_CLK" 6 ns;
#TIMEGRP "to_host" OFFSET=OUT 6 ns AFTER "HOST_CLK";
TIMEGRP "to_host" OFFSET = OUT 20 ns AFTER "CODEC_X2_CLK";

View File

@ -21,6 +21,7 @@
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
library UNISIM;
use UNISIM.vcomponents.all;
@ -30,16 +31,14 @@ entity top is
HOST_DATA : inout std_logic_vector(7 downto 0);
HOST_CAPTURE : out std_logic;
HOST_DISABLE : in std_logic;
HOST_DIRECTION : in std_logic;
HOST_DIRECTION : in std_logic;
HOST_DECIM_SEL : in std_logic_vector(2 downto 0);
DA : in std_logic_vector(7 downto 0);
DD : out std_logic_vector(9 downto 0);
CODEC_CLK : in std_logic;
CODEC_X2_CLK : in std_logic;
B1AUX : inout std_logic_vector(16 downto 9);
B2AUX : inout std_logic_vector(16 downto 1)
CODEC_X2_CLK : in std_logic
);
end top;
@ -60,11 +59,12 @@ architecture Behavioral of top is
signal data_from_host_i : std_logic_vector(7 downto 0);
signal data_to_host_o : std_logic_vector(7 downto 0);
signal decimate_count : std_logic_vector(2 downto 0) := "111";
signal decimate_sel_i : std_logic_vector(2 downto 0);
signal decimate_en : std_logic;
begin
B1AUX <= (others => '0');
B2AUX <= (others => '0');
------------------------------------------------
-- Codec interface
@ -93,13 +93,36 @@ begin
host_data_enable_i <= not HOST_DISABLE;
transfer_direction_i <= to_dac when HOST_DIRECTION = '1'
else from_adc;
------------------------------------------------
decimate_sel_i <= HOST_DECIM_SEL;
------------------------------------------------
decimate_en <= '1' when decimate_count = "111" else '0';
process(host_clk_i)
begin
if rising_edge(host_clk_i) then
if codec_clk_i = '1' then
if decimate_count = "111" or host_data_enable_i = '0' then
decimate_count <= decimate_sel_i;
else
decimate_count <= decimate_count + 1;
end if;
end if;
end if;
end process;
process(host_clk_i)
begin
if rising_edge(host_clk_i) then
data_to_host_o <= adc_data_i;
if codec_clk_i = '1' then
-- I: non-inverted between MAX2837 and MAX5864
data_to_host_o <= adc_data_i xor X"80";
else
-- Q: inverted between MAX2837 and MAX5864
data_to_host_o <= adc_data_i xor X"7f";
end if;
end if;
end process;
@ -107,14 +130,14 @@ begin
begin
if rising_edge(host_clk_i) then
if transfer_direction_i = to_dac then
dac_data_o <= data_from_host_i & "00";
dac_data_o <= (data_from_host_i xor X"7f") & "11";
else
dac_data_o <= (dac_data_o'high => '1', others => '0');
dac_data_o <= (dac_data_o'high => '0', others => '1');
end if;
end if;
end process;
process(host_clk_i, codec_clk_i)
process(host_clk_i)
begin
if rising_edge(host_clk_i) then
if transfer_direction_i = to_dac then
@ -123,7 +146,7 @@ begin
end if;
else
if codec_clk_i = '0' then
host_data_capture_o <= host_data_enable_i;
host_data_capture_o <= host_data_enable_i and decimate_en;
end if;
end if;
end if;

View File

@ -1,22 +1,22 @@
--
-- 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.
-- 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.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
@ -31,13 +31,12 @@ ARCHITECTURE behavior OF top_tb IS
HOST_DATA : INOUT std_logic_vector(7 downto 0);
HOST_CAPTURE : OUT std_logic;
HOST_DISABLE : IN std_logic;
HOST_DIRECTION : IN std_logic;
HOST_DIRECTION : IN std_logic;
HOST_DECIM_SEL : IN std_logic_vector(2 downto 0);
DA : IN std_logic_vector(7 downto 0);
DD : OUT std_logic_vector(9 downto 0);
CODEC_CLK : IN std_logic;
CODEC_X2_CLK : IN std_logic;
B1AUX : INOUT std_logic_vector(16 downto 9);
B2AUX : INOUT std_logic_vector(16 downto 1)
CODEC_X2_CLK : IN std_logic
);
END COMPONENT;
@ -46,12 +45,11 @@ ARCHITECTURE behavior OF top_tb IS
signal CODEC_CLK : std_logic := '0';
signal CODEC_X2_CLK : std_logic := '0';
signal HOST_DISABLE : std_logic := '1';
signal HOST_DIRECTION : std_logic := '0';
signal HOST_DIRECTION : std_logic := '0';
signal HOST_DECIM_SEL : std_logic_vector(2 downto 0) := "010";
--BiDirs
signal HOST_DATA : std_logic_vector(7 downto 0);
signal B1AUX : std_logic_vector(16 downto 9);
signal B2AUX : std_logic_vector(16 downto 1);
--Outputs
signal DD : std_logic_vector(9 downto 0);
@ -63,13 +61,12 @@ begin
HOST_DATA => HOST_DATA,
HOST_CAPTURE => HOST_CAPTURE,
HOST_DISABLE => HOST_DISABLE,
HOST_DIRECTION => HOST_DIRECTION,
HOST_DIRECTION => HOST_DIRECTION,
HOST_DECIM_SEL => HOST_DECIM_SEL,
DA => DA,
DD => DD,
CODEC_CLK => CODEC_CLK,
CODEC_X2_CLK => CODEC_X2_CLK,
B1AUX => B1AUX,
B2AUX => B2AUX
CODEC_X2_CLK => CODEC_X2_CLK
);
clk_process :process
@ -90,11 +87,11 @@ begin
begin
wait until rising_edge(CODEC_CLK);
wait for 9 ns;
DA <= (others => '0');
DA <= "00000000";
wait until falling_edge(CODEC_CLK);
wait for 9 ns;
DA <= (others => '1');
DA <= "00000001";
end process;
@ -132,4 +129,4 @@ begin
wait;
end process;
end;
end;

View File

@ -1,42 +0,0 @@
# Hey Emacs, this is a -*- makefile -*-
#
# Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
#
# This file is part of HackRF.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
BINARY = cpldjtagprog_rom_to_ram
SRC_DIR = cpldjtagprog
SRC = cpldjtagprog.c \
../common/hackrf_core.c \
../common/si5351c.c \
../common/max2837.c \
../common/cpld_jtag.c \
../common/xapp058/lenval.c \
../common/xapp058/micro.c \
../common/xapp058/ports.c
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
%.o: ../$(SRC_DIR)/%.c Makefile
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
include ../common/Makefile_inc.mk

View File

@ -1 +0,0 @@
This is a test program for CPLD JTAG programming.

View File

@ -20,13 +20,30 @@
# Boston, MA 02110-1301, USA.
#
BINARY = hackrf_usb
ifeq ($(RUN_FROM),RAM)
BINARY = hackrf_usb_ram
else
BINARY = hackrf_usb_rom_to_ram
endif
SRC = $(BINARY).c \
usb.c \
usb_request.c \
usb_standard_request.c \
SRC_M4_C = hackrf_usb.c \
../common/rf_path.c \
../common/tuning.c \
../common/streaming.c \
sgpio_isr.c \
usb_bulk_buffer.c \
../common/usb.c \
../common/usb_request.c \
../common/usb_standard_request.c \
usb_descriptor.c \
usb_device.c \
usb_endpoint.c \
usb_api_board_info.c \
usb_api_cpld.c \
usb_api_register.c \
usb_api_spiflash.c \
usb_api_transceiver.c \
../common/usb_queue.c \
../common/fault_handler.c \
../common/hackrf_core.c \
../common/sgpio.c \

View File

@ -1,45 +0,0 @@
# Hey Emacs, this is a -*- makefile -*-
#
# Copyright 2012 Jared Boone <jared@sharebrained.com>
#
# This file is part of HackRF.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
BINARY = hackrf_usb_rom_to_ram
SRC = hackrf_usb.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 \
../common/w25q80bv.c \
../common/cpld_jtag.c \
../common/xapp058/lenval.c \
../common/xapp058/micro.c \
../common/xapp058/ports.c \
../common/rom_iap.c
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
include ../common/Makefile_inc.mk

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "sgpio_isr.h"
#include <libopencm3/lpc43xx/sgpio.h>
#include "usb_bulk_buffer.h"
void sgpio_isr_rx() {
SGPIO_CLR_STATUS_1 = (1 << SGPIO_SLICE_A);
uint32_t* const p = (uint32_t*)&usb_bulk_buffer[usb_bulk_buffer_offset];
__asm__(
"ldr r0, [%[SGPIO_REG_SS], #44]\n\t"
"str r0, [%[p], #0]\n\t"
"ldr r0, [%[SGPIO_REG_SS], #20]\n\t"
"str r0, [%[p], #4]\n\t"
"ldr r0, [%[SGPIO_REG_SS], #40]\n\t"
"str r0, [%[p], #8]\n\t"
"ldr r0, [%[SGPIO_REG_SS], #8]\n\t"
"str r0, [%[p], #12]\n\t"
"ldr r0, [%[SGPIO_REG_SS], #36]\n\t"
"str r0, [%[p], #16]\n\t"
"ldr r0, [%[SGPIO_REG_SS], #16]\n\t"
"str r0, [%[p], #20]\n\t"
"ldr r0, [%[SGPIO_REG_SS], #32]\n\t"
"str r0, [%[p], #24]\n\t"
"ldr r0, [%[SGPIO_REG_SS], #0]\n\t"
"str r0, [%[p], #28]\n\t"
:
: [SGPIO_REG_SS] "l" (SGPIO_PORT_BASE + 0x100),
[p] "l" (p)
: "r0"
);
usb_bulk_buffer_offset = (usb_bulk_buffer_offset + 32) & usb_bulk_buffer_mask;
}
void sgpio_isr_tx() {
SGPIO_CLR_STATUS_1 = (1 << SGPIO_SLICE_A);
uint32_t* const p = (uint32_t*)&usb_bulk_buffer[usb_bulk_buffer_offset];
__asm__(
"ldr r0, [%[p], #0]\n\t"
"str r0, [%[SGPIO_REG_SS], #44]\n\t"
"ldr r0, [%[p], #4]\n\t"
"str r0, [%[SGPIO_REG_SS], #20]\n\t"
"ldr r0, [%[p], #8]\n\t"
"str r0, [%[SGPIO_REG_SS], #40]\n\t"
"ldr r0, [%[p], #12]\n\t"
"str r0, [%[SGPIO_REG_SS], #8]\n\t"
"ldr r0, [%[p], #16]\n\t"
"str r0, [%[SGPIO_REG_SS], #36]\n\t"
"ldr r0, [%[p], #20]\n\t"
"str r0, [%[SGPIO_REG_SS], #16]\n\t"
"ldr r0, [%[p], #24]\n\t"
"str r0, [%[SGPIO_REG_SS], #32]\n\t"
"ldr r0, [%[p], #28]\n\t"
"str r0, [%[SGPIO_REG_SS], #0]\n\t"
:
: [SGPIO_REG_SS] "l" (SGPIO_PORT_BASE + 0x100),
[p] "l" (p)
: "r0"
);
usb_bulk_buffer_offset = (usb_bulk_buffer_offset + 32) & usb_bulk_buffer_mask;
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __SGPIO_ISR_H__
#define __SGPIO_ISR_H__
void sgpio_isr_rx();
void sgpio_isr_tx();
#endif/*__SGPIO_ISR_H__*/

View File

@ -0,0 +1,93 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "usb_api_board_info.h"
#include <hackrf_core.h>
#include <rom_iap.h>
#include <usb_queue.h>
#include <stddef.h>
#include <string.h>
char version_string[] = VERSION_STRING;
usb_request_status_t usb_vendor_request_read_board_id(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
if (stage == USB_TRANSFER_STAGE_SETUP) {
endpoint->buffer[0] = BOARD_ID;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
}
return USB_REQUEST_STATUS_OK;
}
usb_request_status_t usb_vendor_request_read_version_string(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
uint8_t length;
if (stage == USB_TRANSFER_STAGE_SETUP) {
length = (uint8_t)strlen(version_string);
usb_transfer_schedule_block(endpoint->in, version_string, length, NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
}
return USB_REQUEST_STATUS_OK;
}
usb_request_status_t usb_vendor_request_read_partid_serialno(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
uint8_t length;
read_partid_serialno_t read_partid_serialno;
iap_cmd_res_t iap_cmd_res;
if (stage == USB_TRANSFER_STAGE_SETUP)
{
/* Read IAP Part Number Identification */
iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_PART_ID_NO;
iap_cmd_call(&iap_cmd_res);
if(iap_cmd_res.status_res.status_ret != CMD_SUCCESS)
return USB_REQUEST_STATUS_STALL;
read_partid_serialno.part_id[0] = iap_cmd_res.status_res.iap_result[0];
read_partid_serialno.part_id[1] = iap_cmd_res.status_res.iap_result[1];
/* Read IAP Serial Number Identification */
iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_SERIAL_NO;
iap_cmd_call(&iap_cmd_res);
if(iap_cmd_res.status_res.status_ret != CMD_SUCCESS)
return USB_REQUEST_STATUS_STALL;
read_partid_serialno.serial_no[0] = iap_cmd_res.status_res.iap_result[0];
read_partid_serialno.serial_no[1] = iap_cmd_res.status_res.iap_result[1];
read_partid_serialno.serial_no[2] = iap_cmd_res.status_res.iap_result[2];
read_partid_serialno.serial_no[3] = iap_cmd_res.status_res.iap_result[3];
length = (uint8_t)sizeof(read_partid_serialno_t);
usb_transfer_schedule_block(endpoint->in, &read_partid_serialno, length,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
}
return USB_REQUEST_STATUS_OK;
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __USB_API_BOARD_INFO_H__
#define __USB_API_BOARD_INFO_H__
#include <stdint.h>
#include <usb_type.h>
#include <usb_request.h>
typedef struct {
uint32_t part_id[2];
uint32_t serial_no[4];
} read_partid_serialno_t;
usb_request_status_t usb_vendor_request_read_board_id(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_read_version_string(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_read_partid_serialno(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
#endif /* end of include guard: __USB_API_BOARD_INFO_H__ */

View File

@ -0,0 +1,94 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "usb_api_cpld.h"
#include <libopencm3/lpc43xx/gpio.h>
#include <hackrf_core.h>
#include <cpld_jtag.h>
#include <usb_queue.h>
#include "usb_endpoint.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
volatile bool start_cpld_update = false;
uint8_t cpld_xsvf_buffer[512];
volatile bool cpld_wait = false;
static void cpld_buffer_refilled(void* user_data, unsigned int length)
{
cpld_wait = false;
}
static void refill_cpld_buffer(void)
{
cpld_wait = true;
usb_transfer_schedule(
&usb_endpoint_bulk_out,
cpld_xsvf_buffer,
sizeof(cpld_xsvf_buffer),
cpld_buffer_refilled,
NULL
);
// Wait until transfer finishes
while (cpld_wait);
}
void cpld_update(void)
{
#define WAIT_LOOP_DELAY (6000000)
#define ALL_LEDS (PIN_LED1|PIN_LED2|PIN_LED3)
int i;
int error;
usb_queue_flush_endpoint(&usb_endpoint_bulk_in);
usb_queue_flush_endpoint(&usb_endpoint_bulk_out);
refill_cpld_buffer();
error = cpld_jtag_program(sizeof(cpld_xsvf_buffer),
cpld_xsvf_buffer,
refill_cpld_buffer);
if(error == 0)
{
/* blink LED1, LED2, and LED3 on success */
while (1)
{
gpio_set(PORT_LED1_3, ALL_LEDS); /* LEDs on */
for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */
__asm__("nop");
gpio_clear(PORT_LED1_3, ALL_LEDS); /* LEDs off */
for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */
__asm__("nop");
}
}else
{
/* LED3 (Red) steady on error */
gpio_set(PORT_LED1_3, PIN_LED3); /* LEDs on */
while (1);
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __USB_API_CPLD_H__
#define __USB_API_CPLD_H__
#include <stdbool.h>
extern volatile bool start_cpld_update;
void cpld_update(void);
#endif /* end of include guard: __USB_API_CPLD_H__ */

View File

@ -0,0 +1,147 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "usb_api_register.h"
#include <usb_queue.h>
#include <max2837.h>
#include <si5351c.h>
#include <rffc5071.h>
#include <stddef.h>
#include <stdint.h>
usb_request_status_t usb_vendor_request_write_max2837(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
) {
if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < MAX2837_NUM_REGS ) {
if( endpoint->setup.value < MAX2837_DATA_REGS_MAX_VALUE ) {
max2837_reg_write(endpoint->setup.index, endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
}
}
return USB_REQUEST_STATUS_STALL;
} else {
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_read_max2837(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
) {
if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < MAX2837_NUM_REGS ) {
const uint16_t value = max2837_reg_read(endpoint->setup.index);
endpoint->buffer[0] = value & 0xff;
endpoint->buffer[1] = value >> 8;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_STALL;
} else {
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_write_si5351c(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
) {
if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < 256 ) {
if( endpoint->setup.value < 256 ) {
si5351c_write_single(endpoint->setup.index, endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
}
}
return USB_REQUEST_STATUS_STALL;
} else {
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_read_si5351c(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
) {
if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < 256 ) {
const uint8_t value = si5351c_read_single(endpoint->setup.index);
endpoint->buffer[0] = value;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_STALL;
} else {
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_write_rffc5071(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
) {
if( stage == USB_TRANSFER_STAGE_SETUP )
{
if( endpoint->setup.index < RFFC5071_NUM_REGS )
{
rffc5071_reg_write(endpoint->setup.index, endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_STALL;
} else {
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_read_rffc5071(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
) {
uint16_t value;
if( stage == USB_TRANSFER_STAGE_SETUP )
{
if( endpoint->setup.index < RFFC5071_NUM_REGS )
{
value = rffc5071_reg_read(endpoint->setup.index);
endpoint->buffer[0] = value & 0xff;
endpoint->buffer[1] = value >> 8;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_STALL;
} else {
return USB_REQUEST_STATUS_OK;
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __USB_API_REGISTER_H__
#define __USB_API_REGISTER_H__
#include <usb_type.h>
#include <usb_request.h>
usb_request_status_t usb_vendor_request_write_max2837(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
);
usb_request_status_t usb_vendor_request_read_max2837(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
);
usb_request_status_t usb_vendor_request_write_si5351c(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
);
usb_request_status_t usb_vendor_request_read_si5351c(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
);
usb_request_status_t usb_vendor_request_write_rffc5071(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
);
usb_request_status_t usb_vendor_request_read_rffc5071(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
);
#endif /* end of include guard: __USB_API_REGISTER_H__ */

View File

@ -0,0 +1,131 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "usb_api_spiflash.h"
#include "usb_queue.h"
#include <stddef.h>
#include <w25q80bv.h>
uint8_t spiflash_buffer[W25Q80BV_PAGE_LEN];
usb_request_status_t usb_vendor_request_erase_spiflash(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
//FIXME This should refuse to run if executing from SPI flash.
if (stage == USB_TRANSFER_STAGE_SETUP) {
w25q80bv_setup();
/* only chip erase is implemented */
w25q80bv_chip_erase();
usb_transfer_schedule_ack(endpoint->in);
//FIXME probably should undo w25q80bv_setup()
}
return USB_REQUEST_STATUS_OK;
}
usb_request_status_t usb_vendor_request_write_spiflash(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
uint32_t addr = 0;
uint16_t len = 0;
//FIXME This should refuse to run if executing from SPI flash.
if (stage == USB_TRANSFER_STAGE_SETUP) {
addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length;
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES)
|| ((addr + len) > W25Q80BV_NUM_BYTES)) {
return USB_REQUEST_STATUS_STALL;
} else {
usb_transfer_schedule_block(endpoint->out, &spiflash_buffer[0], len,
NULL, NULL);
w25q80bv_setup();
return USB_REQUEST_STATUS_OK;
}
} else if (stage == USB_TRANSFER_STAGE_DATA) {
addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length;
/* This check is redundant but makes me feel better. */
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES)
|| ((addr + len) > W25Q80BV_NUM_BYTES)) {
return USB_REQUEST_STATUS_STALL;
} else {
w25q80bv_program(addr, len, &spiflash_buffer[0]);
usb_transfer_schedule_ack(endpoint->in);
//FIXME probably should undo w25q80bv_setup()
return USB_REQUEST_STATUS_OK;
}
} else {
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_read_spiflash(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
uint32_t i;
uint32_t addr;
uint16_t len;
uint8_t* u8_addr_pt;
if (stage == USB_TRANSFER_STAGE_SETUP)
{
addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length;
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES)
|| ((addr + len) > W25Q80BV_NUM_BYTES)) {
return USB_REQUEST_STATUS_STALL;
} else {
/* TODO flush SPIFI "cache" before to read the SPIFI memory */
u8_addr_pt = (uint8_t*)(addr + SPIFI_DATA_UNCACHED_BASE);
for(i=0; i<len; i++)
{
spiflash_buffer[i] = u8_addr_pt[i];
}
usb_transfer_schedule_block(endpoint->in, &spiflash_buffer[0], len,
NULL, NULL);
return USB_REQUEST_STATUS_OK;
}
} else if (stage == USB_TRANSFER_STAGE_DATA)
{
addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length;
/* This check is redundant but makes me feel better. */
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES)
|| ((addr + len) > W25Q80BV_NUM_BYTES))
{
return USB_REQUEST_STATUS_STALL;
} else
{
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
} else
{
return USB_REQUEST_STATUS_OK;
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __USB_API_SPIFLASH_H__
#define __USB_API_SPIFLASH_H__
#include <usb_type.h>
#include <usb_request.h>
usb_request_status_t usb_vendor_request_erase_spiflash(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_write_spiflash(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_read_spiflash(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
#endif /* end of include guard: __USB_API_SPIFLASH_H__ */

View File

@ -0,0 +1,189 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "usb_api_transceiver.h"
#include <libopencm3/lpc43xx/gpio.h>
#include <max2837.h>
#include <rf_path.h>
#include <tuning.h>
#include <usb.h>
#include <usb_queue.h>
#include <stddef.h>
#include "usb_endpoint.h"
typedef struct {
uint32_t freq_mhz;
uint32_t freq_hz;
} set_freq_params_t;
set_freq_params_t set_freq_params;
typedef struct {
uint32_t freq_hz;
uint32_t divider;
} set_sample_r_params_t;
set_sample_r_params_t set_sample_r_params;
usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage
) {
if( stage == USB_TRANSFER_STAGE_SETUP ) {
const uint32_t bandwidth = (endpoint->setup.index << 16) | endpoint->setup.value;
if( baseband_filter_bandwidth_set(bandwidth) ) {
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_STALL;
} else {
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_set_freq(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage)
{
if (stage == USB_TRANSFER_STAGE_SETUP)
{
usb_transfer_schedule_block(endpoint->out, &set_freq_params, sizeof(set_freq_params_t),
NULL, NULL);
return USB_REQUEST_STATUS_OK;
} else if (stage == USB_TRANSFER_STAGE_DATA)
{
const uint64_t freq = set_freq_params.freq_mhz * 1000000 + set_freq_params.freq_hz;
if( set_freq(freq) )
{
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_STALL;
} else
{
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_set_sample_rate_frac(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage)
{
if (stage == USB_TRANSFER_STAGE_SETUP)
{
usb_transfer_schedule_block(endpoint->out, &set_sample_r_params, sizeof(set_sample_r_params_t),
NULL, NULL);
return USB_REQUEST_STATUS_OK;
} else if (stage == USB_TRANSFER_STAGE_DATA)
{
if( sample_rate_frac_set(set_sample_r_params.freq_hz * 2, set_sample_r_params.divider ) )
{
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_STALL;
} else
{
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_set_amp_enable(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
if (stage == USB_TRANSFER_STAGE_SETUP) {
switch (endpoint->setup.value) {
case 0:
rf_path_set_lna(0);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
case 1:
rf_path_set_lna(1);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
default:
return USB_REQUEST_STATUS_STALL;
}
} else {
return USB_REQUEST_STATUS_OK;
}
}
usb_request_status_t usb_vendor_request_set_lna_gain(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage)
{
if( stage == USB_TRANSFER_STAGE_SETUP ) {
const uint8_t value = max2837_set_lna_gain(endpoint->setup.index);
endpoint->buffer[0] = value;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_OK;
}
usb_request_status_t usb_vendor_request_set_vga_gain(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
if( stage == USB_TRANSFER_STAGE_SETUP ) {
const uint8_t value = max2837_set_vga_gain(endpoint->setup.index);
endpoint->buffer[0] = value;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_OK;
}
usb_request_status_t usb_vendor_request_set_txvga_gain(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{
if( stage == USB_TRANSFER_STAGE_SETUP ) {
const uint8_t value = max2837_set_txvga_gain(endpoint->setup.index);
endpoint->buffer[0] = value;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
usb_transfer_schedule_ack(endpoint->out);
return USB_REQUEST_STATUS_OK;
}
return USB_REQUEST_STATUS_OK;
}
usb_request_status_t usb_vendor_request_set_if_freq(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage
) {
if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( set_freq_if((uint32_t)endpoint->setup.index * 1000 * 1000) ) {
usb_transfer_schedule_ack(endpoint->in);
} else {
return USB_REQUEST_STATUS_STALL;
}
}
return USB_REQUEST_STATUS_OK;
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __USB_API_TRANSCEIVER_H__
#define __USB_API_TRANSCEIVER_H__
#include <hackrf_core.h>
#include <usb_type.h>
#include <usb_request.h>
usb_request_status_t usb_vendor_request_set_transceiver_mode(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_set_freq(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_set_sample_rate_frac(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_set_amp_enable(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_set_lna_gain(
usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_set_vga_gain(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_set_txvga_gain(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
usb_request_status_t usb_vendor_request_set_if_freq(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
#endif/*__USB_API_TRANSCEIVER_H__*/

View File

@ -0,0 +1,26 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "usb_bulk_buffer.h"
const uint32_t usb_bulk_buffer_mask = 32768 - 1;
volatile uint32_t usb_bulk_buffer_offset = 0;

View File

@ -0,0 +1,38 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __USB_BULK_BUFFER_H__
#define __USB_BULK_BUFFER_H__
#include <stdint.h>
/* Address of usb_bulk_buffer is set in ldscripts. If you change the name of this
* variable, it won't be where it needs to be in the processor's address space,
* unless you also adjust the ldscripts.
*/
extern uint8_t usb_bulk_buffer[32768];
extern const uint32_t usb_bulk_buffer_mask;
extern volatile uint32_t usb_bulk_buffer_offset;
#endif/*__USB_BULK_BUFFER_H__*/

View File

@ -38,117 +38,191 @@
#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
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
0x02 // 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
10, // bLength
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, // bDescriptorType
USB_WORD(0x0200), // bcdUSB
0x00, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
64, // bMaxPacketSize0
0x02, // 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
9, // bLength
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
USB_WORD(32), // wTotalLength
0x01, // bNumInterfaces
0x01, // bConfigurationValue
0x03, // 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
9, // bLength
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
USB_WORD(32), // wTotalLength
0x01, // bNumInterfaces
0x01, // bConfigurationValue
0x03, // 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_configuration_cpld_update_full_speed[] = {
9, // bLength
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
USB_WORD(32), // wTotalLength
0x01, // bNumInterfaces
0x02, // bConfigurationValue
0x04, // 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_cpld_update_high_speed[] = {
9, // bLength
USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType
USB_WORD(32), // wTotalLength
0x01, // bNumInterfaces
0x02, // bConfigurationValue
0x04, // 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
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
40, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'G', 0x00,
'r', 0x00,
'e', 0x00,
@ -171,8 +245,8 @@ uint8_t usb_descriptor_string_manufacturer[] = {
};
uint8_t usb_descriptor_string_product[] = {
14, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
14, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'H', 0x00,
'a', 0x00,
'c', 0x00,
@ -181,10 +255,44 @@ uint8_t usb_descriptor_string_product[] = {
'F', 0x00,
};
uint8_t usb_descriptor_string_config1_description[] = {
24, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'T', 0x00,
'r', 0x00,
'a', 0x00,
'n', 0x00,
's', 0x00,
'c', 0x00,
'e', 0x00,
'i', 0x00,
'v', 0x00,
'e', 0x00,
'r', 0x00,
};
uint8_t usb_descriptor_string_config2_description[] = {
24, // bLength
USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType
'C', 0x00,
'P', 0x00,
'L', 0x00,
'D', 0x00,
' ', 0x00,
'u', 0x00,
'p', 0x00,
'd', 0x00,
'a', 0x00,
't', 0x00,
'e', 0x00,
};
uint8_t* const usb_descriptor_strings[] = {
usb_descriptor_string_languages,
usb_descriptor_string_manufacturer,
usb_descriptor_string_product,
usb_descriptor_string_config1_description,
usb_descriptor_string_config2_description,
0, // TERMINATOR
};

View File

@ -25,6 +25,8 @@ 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_configuration_cpld_update_full_speed[];
extern uint8_t usb_descriptor_configuration_cpld_update_high_speed[];
extern uint8_t usb_descriptor_string_languages[];
extern uint8_t usb_descriptor_string_manufacturer[];
extern uint8_t usb_descriptor_string_product[];

View File

@ -0,0 +1,67 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "usb_device.h"
#include <usb_type.h>
#include "usb_descriptor.h"
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_configuration_cpld_update_full_speed = {
.number = 2,
.speed = USB_SPEED_FULL,
.descriptor = usb_descriptor_configuration_cpld_update_full_speed,
};
usb_configuration_t usb_configuration_cpld_update_high_speed = {
.number = 2,
.speed = USB_SPEED_HIGH,
.descriptor = usb_descriptor_configuration_cpld_update_high_speed,
};
usb_configuration_t* usb_configurations[] = {
&usb_configuration_high_speed,
&usb_configuration_full_speed,
&usb_configuration_cpld_update_full_speed,
&usb_configuration_cpld_update_high_speed,
0,
};
usb_device_t usb_device = {
.descriptor = usb_descriptor_device,
.descriptor_strings = usb_descriptor_strings,
.qualifier_descriptor = usb_descriptor_device_qualifier,
.configurations = &usb_configurations,
.configuration = 0,
};

View File

@ -0,0 +1,30 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __USB_DEVICE_H__
#define __USB_DEVICE_H__
#include <usb_type.h>
extern usb_device_t usb_device;
#endif /* end of include guard: __USB_DEVICE_H__ */

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#include "usb_endpoint.h"
#include <usb_request.h>
#include "usb_device.h"
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_DEFINE_QUEUE(usb_endpoint_control_out, 4);
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,
};
static USB_DEFINE_QUEUE(usb_endpoint_control_in, 4);
// 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 = usb_queue_transfer_complete
};
static USB_DEFINE_QUEUE(usb_endpoint_bulk_in, 1);
usb_endpoint_t usb_endpoint_bulk_out = {
.address = 0x02,
.device = &usb_device,
.in = 0,
.out = &usb_endpoint_bulk_out,
.setup_complete = 0,
.transfer_complete = usb_queue_transfer_complete
};
static USB_DEFINE_QUEUE(usb_endpoint_bulk_out, 1);

View File

@ -0,0 +1,41 @@
/*
* Copyright 2012 Jared Boone
* Copyright 2013 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.
*/
#ifndef __USB_ENDPOINT_H__
#define __USB_ENDPOINT_H__
#include <usb_type.h>
#include <usb_queue.h>
extern usb_endpoint_t usb_endpoint_control_out;
extern USB_DECLARE_QUEUE(usb_endpoint_control_out);
extern usb_endpoint_t usb_endpoint_control_in;
extern USB_DECLARE_QUEUE(usb_endpoint_control_in);
extern usb_endpoint_t usb_endpoint_bulk_in;
extern USB_DECLARE_QUEUE(usb_endpoint_bulk_in);
extern usb_endpoint_t usb_endpoint_bulk_out;
extern USB_DECLARE_QUEUE(usb_endpoint_bulk_out);
#endif /* end of include guard: __USB_ENDPOINT_H__ */

View File

@ -1,53 +0,0 @@
# Hey Emacs, this is a -*- makefile -*-
#
# Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
#
# This file is part of HackRF.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
BINARY = hackrf_usb_rom_to_ram
SRC_DIR = hackrf_usb
SRC = hackrf_usb.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 \
../common/w25q80bv.c \
../common/cpld_jtag.c \
../common/xapp058/lenval.c \
../common/xapp058/micro.c \
../common/xapp058/ports.c \
../common/rom_iap.c
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
%.o: ../$(SRC_DIR)/%.c Makefile
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
include ../common/Makefile_inc.mk

View File

@ -4,8 +4,11 @@ BINARY = mixertx
SRC = $(BINARY).c \
../common/hackrf_core.c \
../common/rf_path.c \
../common/sgpio.c \
../common/si5351c.c \
../common/max2837.c \
../common/max5864.c \
../common/rffc5071.c
include ../common/Makefile_inc.mk

View File

@ -24,6 +24,8 @@ BINARY = sgpio-rx
SRC = $(BINARY).c \
../common/hackrf_core.c \
../common/tuning.c \
../common/rf_path.c \
../common/sgpio.c \
../common/si5351c.c \
../common/max2837.c \

View File

@ -21,19 +21,16 @@
*/
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/sgpio.h>
#include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/cm3/scs.h>
#include <hackrf_core.h>
#include <max5864.h>
#include <max2837.h>
#include <rffc5071.h>
#include <rf_path.h>
#include <sgpio.h>
#include <tuning.h>
void tx_test() {
sgpio_configure(TRANSCEIVER_MODE_TX, false);
sgpio_set_slice_mode(false);
sgpio_configure(TRANSCEIVER_MODE_TX);
// LSB goes out first, samples are 0x<Q1><I1><Q0><I0>
volatile uint32_t buffer[] = {
@ -54,7 +51,8 @@ void tx_test() {
}
void rx_test() {
sgpio_configure(TRANSCEIVER_MODE_RX, false);
sgpio_set_slice_mode(false);
sgpio_configure(TRANSCEIVER_MODE_RX);
volatile uint32_t buffer[4096];
uint32_t i = 0;
@ -90,28 +88,17 @@ void rx_test() {
int main(void) {
const uint32_t freq = 2700000000U;
uint8_t switchctrl = 0;
const uint64_t freq = 2700000000U;
pin_setup();
enable_1v8_power();
cpu_clock_init();
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); // 500 MHz
rf_path_init();
rf_path_set_direction(RF_PATH_DIRECTION_RX);
max2837_set_frequency(freq);
max2837_start();
max2837_rx();
set_freq(freq);
ssp1_set_mode_max5864();
max5864_xcvr();
rx_test();
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */

View File

@ -20,13 +20,15 @@
# Boston, MA 02110-1301, USA.
#
BINARY = sgpio
BINARY = sgpio_test
SRC = $(BINARY).c \
../common/hackrf_core.c \
../common/rf_path.c \
../common/sgpio.c \
../common/si5351c.c \
../common/max2837.c \
../common/max5864.c
../common/max5864.c \
../common/rffc5071.c
include ../common/Makefile_inc.mk

View File

@ -31,7 +31,8 @@
#include <sgpio.h>
void tx_test() {
sgpio_configure(TRANSCEIVER_MODE_TX, false);
sgpio_set_slice_mode(false);
sgpio_configure(TRANSCEIVER_MODE_TX);
// LSB goes out first, samples are 0x<Q1><I1><Q0><I0>
volatile uint32_t buffer[] = {
@ -52,7 +53,8 @@ void tx_test() {
}
void rx_test() {
sgpio_configure(TRANSCEIVER_MODE_RX, false);
sgpio_set_slice_mode(false);
sgpio_configure(TRANSCEIVER_MODE_RX);
volatile uint32_t buffer[4096];
uint32_t i = 0;

View File

@ -25,8 +25,8 @@ BINARY = sgpio_passthrough
SRC = $(BINARY).c \
../common/hackrf_core.c \
../common/sgpio.c \
../common/si5351c.c \
../common/max2837.c
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
include ../common/Makefile_inc.mk

View File

@ -169,7 +169,7 @@ void test_sgpio_sliceA_D(void)
/* SGPIO pin 14 outputs slice H bit 0. */
/* SGPIO pin 15 outputs slice P bit 0. */
/*******************************************************************************/
const u8 slice_preset_tab[16] =
const uint8_t slice_preset_tab[16] =
{
0, /* Idx00 = Slice A => SGPIO0 Freq Div by 1=0 */
8, /* Idx01 = Slice B => SGPIO8 Freq Div by 9=8 */

View File

@ -4,7 +4,11 @@ BINARY = simpletx
SRC = $(BINARY).c \
../common/hackrf_core.c \
../common/rf_path.c \
../common/sgpio.c \
../common/si5351c.c \
../common/max2837.c
../common/max2837.c \
../common/max5864.c \
../common/rffc5071.c
include ../common/Makefile_inc.mk

View File

@ -25,6 +25,7 @@ BINARY = spiflash
SRC = $(BINARY).c \
../common/hackrf_core.c \
../common/sgpio.c \
../common/si5351c.c \
../common/max2837.c \
../common/w25q80bv.c

View File

@ -4,7 +4,11 @@ BINARY = startup
SRC = $(BINARY).c \
../common/hackrf_core.c \
../common/rf_path.c \
../common/sgpio.c \
../common/si5351c.c \
../common/max2837.c
../common/max2837.c \
../common/max5864.c \
../common/rffc5071.c
include ../common/Makefile_inc.mk

View File

@ -4,7 +4,11 @@ BINARY = startup_systick
SRC = $(BINARY).c \
../common/hackrf_core.c \
../common/rf_path.c \
../common/sgpio.c \
../common/si5351c.c \
../common/max2837.c
../common/max2837.c \
../common/max5864.c \
../common/rffc5071.c
include ../common/Makefile_inc.mk

View File

@ -5,7 +5,11 @@ BINARY = startup_systick_perfo_SPIFI
SRC = startup_systick.c \
perf_mips.c \
../common/hackrf_core.c \
../common/rf_path.c \
../common/sgpio.c \
../common/si5351c.c \
../common/max2837.c
../common/max2837.c \
../common/max5864.c \
../common/rffc5071.c
include ../common/Makefile_inc.mk

View File

@ -4,6 +4,9 @@ Test number of instruction per second (MIPS) slow blink ON 1s, OFF 1s
Then after 16s (the 16tests) it blink LED1/2/3 ON/OFF each 250ms.
This example compute the number of instructions per second executed called also MIPS (Millions of Instructions Per Second)
This example code run from SRAM so maximum performance expected is 204MIPS.
See result details in result_exec_from_SRAM.txt
This example code run from SPIFI (SPI Quad mode) and the tests check different loop size to compute the cache size used with SPIFI and estimated to less than 256Bytes (about 128 instructions in best case and in Thumb2).
See result_exec_from_SPIFI.txt for more details.

View File

@ -1,38 +0,0 @@
# Hey Emacs, this is a -*- makefile -*-
#
# Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
#
# This file is part of HackRF.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
BINARY = startup_systick_perfo_rom_to_ram
SRC_DIR = startup_systick_perfo
SRC = startup_systick.c \
perf_mips.c \
../common/hackrf_core.c \
../common/si5351c.c \
../common/max2837.c
LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld
%.o: ../$(SRC_DIR)/%.c Makefile
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
include ../common/Makefile_inc.mk

View File

@ -1,17 +0,0 @@
This program is an example of the startup sequence for HackRF (Jellybean with
Lemondrop attached).
Test number of instruction per second (MIPS) slow blink ON 1s, OFF 1s
Then after 16s (the 16tests) it blink LED1/2/3 ON/OFF each 250ms.
This example compute the number of instructions per second executed called also MIPS (Millions of Instructions Per Second)
This example code run from SRAM so maximum performance expected is 204MIPS.
See result details in result_exec_from_SRAM.txt
Required Lemondrop -> Jellybean connections:
SCL: Lemondrop P7 pin 3 -> Jellybean P6 pin 3
SDA: Lemondrop P7 pin 5 -> Jellybean P6 pin 5
SDA: Lemondrop P7 pin 6 -> Jellybean P6 pin 6
VCC: Lemondrop P4 pin 2, 4, or 6 -> Jellybean P17 pin 2, 4, or 6
1V8: Lemondrop P11 pin 2, 4, or 6 -> Jellybean P16 pin 2, 4, or 6
GND: Lemondrop P5 -> Jellybean P13

73
firmware/tools/check_clock.py Executable file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env python
# Copyright 2013 Jared Boone
#
# Interpret the LPC43xx Clock Generation Unit (CGU) FREQ_MON register
# and display the estimated clock frequency.
#
# 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.
"""
Inside GDB:
(gdb) set {int}0x40050014 = 0x09800000
(gdb) x 0x40050014
0x40050014: 0x091bd000
This script:
./check_clock.py 0x<register value> 0x<RCNT initial value>
"""
import sys
clock_source_names = {
0x00: '32 kHz oscillator',
0x01: 'IRC',
0x02: 'ENET_RX_CLK',
0x03: 'ENET_TX_CLK',
0x04: 'GP_CLKIN',
0x06: 'Crystal oscillator',
0x07: 'PLL0USB',
0x08: 'PLL0AUDIO',
0x09: 'PLL1',
0x0c: 'IDIVA',
0x0d: 'IDIVB',
0x0e: 'IDIVC',
0x0f: 'IDIVD',
0x10: 'IDIVE',
}
reg_value = int(sys.argv[1], 16)
rcnt = int(sys.argv[2], 16)
print('0x%08x' % reg_value)
rcnt_final = reg_value & 0x1ff
fcnt = (reg_value >> 9) & 0x3fff
clock_source = (reg_value >> 24) & 0x1f
fref = 12e6
if rcnt_final != 0:
raise RuntimeError('RCNT did not reach 0')
print('RCNT: %d' % rcnt)
print('FCNT: %d' % fcnt)
print('Fref: %d' % fref)
clock_hz = fcnt / float(rcnt) * fref
clock_mhz = clock_hz / 1e6
clock_name = clock_source_names[clock_source] if clock_source in clock_source_names else 'Reserved'
print('%s: %.3f MHz' % (clock_name, clock_mhz))

382
firmware/tools/dump_cgu.py Executable file
View File

@ -0,0 +1,382 @@
#!/usr/bin/env python
# Copyright 2013 Jared Boone
#
# Display the LPC43xx Clock Generation Unit (CGU) registers in an
# easy-to-read format.
#
# 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.
"""
In GDB:
dump binary memory cgu.bin 0x40050014 0x400500cc
"""
import sys
from struct import unpack
address = 0x40050014
f = open(sys.argv[1], 'read')
d = '\x00' * 20 + f.read()
length = len(d)
f.close()
def print_data(d):
for i in range(0, length, 16):
values = unpack('<IIII', d[i:i+16])
values = ['%08x' % v for v in values]
values_str = ' '.join(values)
line = '%08x: %s' % (address + i, values_str)
print(line)
#print_data(d)
#sys.exit(0)
data = {}
for i in range(0, length, 4):
data[i] = unpack('<I', d[i:i+4])[0]
registers = {
0x14: {
'name': 'FREQ_MON',
'fields': (
('RCNT', 0, 9),
('FCNT', 9, 14),
('MEAS', 23, 1),
('CLK_SEL', 24, 5),
),
},
0x18: {
'name': 'XTAL_OSC_CONTROL',
'fields': (
('ENABLE', 0, 1),
('BYPASS', 1, 1),
('HF', 2, 1)
),
},
0x1c: {
'name': 'PLL0USB_STAT',
'fields': (
('LOCK', 0, 1),
('FR', 1, 1),
),
},
0x20: {
'name': 'PLL0USB_CTRL',
'fields': (
('PD', 0, 1),
('BYPASS', 1, 1),
('DIRECTI', 2, 1),
('DIRECTO', 3, 1),
('CLKEN', 4, 1),
('FRM', 6, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x24: {
'name': 'PLL0USB_MDIV',
'fields': (
('MDEC', 0, 17),
('SELP', 17, 5),
('SELI', 22, 6),
('SELR', 28, 4),
),
},
0x28: {
'name': 'PLL0USB_NP_DIV',
'fields': (
('PDEC', 0, 7),
('NDEC', 12, 10),
),
},
0x40: {
'name': 'PLL1_STAT',
'fields': (
('LOCK', 0, 1),
),
},
0x44: {
'name': 'PLL1_CTRL',
'fields': (
('PD', 0, 1),
('BYPASS', 1, 1),
('FBSEL', 6, 1),
('DIRECT', 7, 1),
('PSEL', 8, 2),
('AUTOBLOCK', 11, 1),
('NSEL', 12, 2),
('MSEL', 16, 8),
('CLK_SEL', 24, 5),
),
},
0x48: {
'name': 'IDIVA_CTRL',
'fields': (
('PD', 0, 1),
('IDIV', 2, 2),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x4C: {
'name': 'IDIVB_CTRL',
'fields': (
('PD', 0, 1),
('IDIV', 2, 4),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x50: {
'name': 'IDIVC_CTRL',
'fields': (
('PD', 0, 1),
('IDIV', 2, 4),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x54: {
'name': 'IDIVD_CTRL',
'fields': (
('PD', 0, 1),
('IDIV', 2, 4),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x58: {
'name': 'IDIVE_CTRL',
'fields': (
('PD', 0, 1),
('IDIV', 2, 8),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x5C: {
'name': 'BASE_SAFE_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x60: {
'name': 'BASE_USB0_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x64: {
'name': 'BASE_PERIPH_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x68: {
'name': 'BASE_USB1_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x6C: {
'name': 'BASE_M4_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x70: {
'name': 'BASE_SPIFI_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x74: {
'name': 'BASE_SPI_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x78: {
'name': 'BASE_PHY_RX_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x7C: {
'name': 'BASE_PHY_TX_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x80: {
'name': 'BASE_APB1_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x84: {
'name': 'BASE_APB3_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x88: {
'name': 'BASE_LCD_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x8C: {
'name': 'BASE_VADC_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x90: {
'name': 'BASE_SDIO_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x94: {
'name': 'BASE_SSP0_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x98: {
'name': 'BASE_SSP1_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0x9C: {
'name': 'BASE_UART0_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0xA0: {
'name': 'BASE_UART1_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0xA4: {
'name': 'BASE_UART2_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0xA8: {
'name': 'BASE_UART3_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0xAC: {
'name': 'BASE_OUT_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0xC0: {
'name': 'BASE_APLL_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0xC4: {
'name': 'BASE_CGU_OUT0_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
0xC8: {
'name': 'BASE_CGU_OUT1_CLK',
'fields': (
('PD', 0, 1),
('AUTOBLOCK', 11, 1),
('CLK_SEL', 24, 5),
),
},
# TODO: Add other CGU registers. I did the ones that were
# valuable to me to debug CPU clock issues.
}
for address in sorted(registers):
register = registers[address]
name = register['name']
fields = register['fields']
value = data[address]
bits = bin(value)[2:].zfill(32)
print('%03x %20s %s = %08x' % (address, name, bits, value))
for field in fields:
name, low_bit, count = field
field_value = (value >> low_bit) & ((1 << count) - 1)
field_bits = bin(field_value)[2:].zfill(count) + ' ' * low_bit
field_bits = field_bits.rjust(32)
print('%03s %20s %s = %8x %s' % ('', '', field_bits, field_value, name))

Some files were not shown because too many files have changed in this diff Show More