From f4b6f08500bd5984f42d975686baa1a90adcd851 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Oct 2012 11:06:39 -0700 Subject: [PATCH 01/12] Fixed incorrect field with for MAX2837 VGAgain_SPI_EN field. For boards that have no B7:B1 connections, this could prove extra problematic...and for boards that do, but aren't driving those pins from the LPC. --- firmware/common/max2837_regs.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/max2837_regs.def b/firmware/common/max2837_regs.def index 96291866..097be4f7 100644 --- a/firmware/common/max2837_regs.def +++ b/firmware/common/max2837_regs.def @@ -133,7 +133,7 @@ __MREG__(MAX2837_LPF_MODE_SEL,6,9,1) // set to enable mode in reg 2 ModeCtrl /* REG 8 */ __MREG__(MAX2837_LNAgain_SPI_EN,8,0,1) // set to override pin control of LNA -__MREG__(MAX2837_VGAgain_SPI_EN,8,1,0) // set to override pin control of VGA +__MREG__(MAX2837_VGAgain_SPI_EN,8,1,1) // set to override pin control of VGA __MREG__(MAX2837_EN_Bias_Trim,8,2,1) // route bias current to bondpad __MREG__(MAX2837_BIAS_TRIM_SPI,8,7,3) // down=00000, up=11111, nom=10000 __MREG__(MAX2837_BIAS_TRIM_CNTRL,8,8,1) // enable BIAS_TRIM_SPI value From 168c92a3d0080a957d17288654b16d7dc407ea45 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Oct 2012 11:07:17 -0700 Subject: [PATCH 02/12] Now that RxVGA gain control is working correctly, gain needs to be backed WAAAY off to get a usable capture in a fairly noisy 2.4GHz environment. --- firmware/common/max2837.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index 633fbca1..8ad9dadf 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -110,7 +110,7 @@ void max2837_setup(void) set_MAX2837_LNAgain_SPI_EN(1); set_MAX2837_LNAgain(MAX2837_LNAgain_MAX); /* maximum gain */ set_MAX2837_VGAgain_SPI_EN(1); - set_MAX2837_VGA(0x00); /* minimum attenuation */ + set_MAX2837_VGA(0x18); /* reasonable gain for noisy 2.4GHz environment */ /* maximum rx output common-mode voltage */ set_MAX2837_BUFF_VCM(MAX2837_BUFF_VCM_1_25); From 57866227bfd1629444a8c3e471a8564c1a9f4e51 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Oct 2012 11:37:54 -0700 Subject: [PATCH 03/12] Remove weird LDSCRIPT that isn't necessary now. Change .bin generation to include only ROM-able sections. TODO: Is there a better way to do the objcopy? It'd be great to put everything in the "rom" region into the .bin, instead of having to list out -j section for each of the sections that go to ROM. --- firmware/common/LPC4330_M4_ram_only.ld | 38 -------------------------- firmware/common/Makefile_inc.mk | 2 +- firmware/usb_performance/Makefile | 1 - 3 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 firmware/common/LPC4330_M4_ram_only.ld diff --git a/firmware/common/LPC4330_M4_ram_only.ld b/firmware/common/LPC4330_M4_ram_only.ld deleted file mode 100644 index 4149fbd7..00000000 --- a/firmware/common/LPC4330_M4_ram_only.ld +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2012 Michael Ossmann - * Copyright 2012 Jared Boone - * - * This file is part of HackRF - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -/* Linker script for HackRF Jellybean (LPC4330, 1M SPI flash, 264K SRAM). */ - -MEMORY -{ - ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 128K - ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 72K - ram_ahb1 (rwx) : ORIGIN = 0x20000000, LENGTH = 16K - /* Removed 32K of AHB SRAM for USB buffer. Straddles two blocks of RAM - * to get performance benefit of having two USB buffers addressable - * simultaneously (on two different buses of the AHB multilayer matrix) - */ - ram_ahb2 (rwx) : ORIGIN = 0x2000C000, LENGTH = 16K -} - -/* Include the common ld script. */ -INCLUDE libopencm3_lpc43xx_ram_only.ld diff --git a/firmware/common/Makefile_inc.mk b/firmware/common/Makefile_inc.mk index 8ea2f6be..58b9588d 100644 --- a/firmware/common/Makefile_inc.mk +++ b/firmware/common/Makefile_inc.mk @@ -80,7 +80,7 @@ flash: $(BINARY).flash %.bin: %.elf @#printf " OBJCOPY $(*).bin\n" - $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin + $(Q)$(OBJCOPY) -Obinary -j .text -j .ARM.exidx $(*).elf $(*).bin %.hex: %.elf @#printf " OBJCOPY $(*).hex\n" diff --git a/firmware/usb_performance/Makefile b/firmware/usb_performance/Makefile index 7222a2f4..cdde8dd1 100644 --- a/firmware/usb_performance/Makefile +++ b/firmware/usb_performance/Makefile @@ -35,5 +35,4 @@ SRC = $(BINARY).c \ ../common/max5864.c \ ../common/rffc5071.c -LDSCRIPT = ../common/LPC4330_M4_ram_only.ld include ../common/Makefile_inc.mk From 4cf0ba236d5f41028a5b526fdb875b1ff1de72cd Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Oct 2012 12:29:03 -0700 Subject: [PATCH 04/12] Extended common Makefile to include targets for DFU file generation and programming. --- firmware/common/Makefile_inc.mk | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/firmware/common/Makefile_inc.mk b/firmware/common/Makefile_inc.mk index 58b9588d..891495c0 100644 --- a/firmware/common/Makefile_inc.mk +++ b/firmware/common/Makefile_inc.mk @@ -75,9 +75,20 @@ all: images images: $(BINARY).images flash: $(BINARY).flash +program: $(BINARY).dfu + $(Q)dfu-util --device 1fc9:000c --alt 0 --download $(BINARY).dfu + %.images: %.bin %.hex %.srec %.list @#echo "*** $* images generated ***" +%.dfu: %.bin + $(Q)rm -f _tmp.dfu _header.bin + $(Q)cp $(*).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(' _header.bin + $(Q)cat _header.bin _tmp.dfu >$(*).dfu + $(Q)rm -f _tmp.dfu _header.bin + %.bin: %.elf @#printf " OBJCOPY $(*).bin\n" $(Q)$(OBJCOPY) -Obinary -j .text -j .ARM.exidx $(*).elf $(*).bin @@ -107,6 +118,8 @@ clean: $(Q)rm -f *.d $(Q)rm -f *.elf $(Q)rm -f *.bin + $(Q)rm -f *.dfu + $(Q)rm -f _tmp.dfu _header.bin $(Q)rm -f *.hex $(Q)rm -f *.srec $(Q)rm -f *.list From 0d53da8593d3cd156a5c6ff00bbf86dbb79b75a2 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sat, 13 Oct 2012 13:59:37 -0600 Subject: [PATCH 05/12] fixed MAX2837 zero length register fields --- firmware/common/max2837_regs.def | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/common/max2837_regs.def b/firmware/common/max2837_regs.def index 96291866..42dbec34 100644 --- a/firmware/common/max2837_regs.def +++ b/firmware/common/max2837_regs.def @@ -133,7 +133,7 @@ __MREG__(MAX2837_LPF_MODE_SEL,6,9,1) // set to enable mode in reg 2 ModeCtrl /* REG 8 */ __MREG__(MAX2837_LNAgain_SPI_EN,8,0,1) // set to override pin control of LNA -__MREG__(MAX2837_VGAgain_SPI_EN,8,1,0) // set to override pin control of VGA +__MREG__(MAX2837_VGAgain_SPI_EN,8,1,1) // set to override pin control of VGA __MREG__(MAX2837_EN_Bias_Trim,8,2,1) // route bias current to bondpad __MREG__(MAX2837_BIAS_TRIM_SPI,8,7,3) // down=00000, up=11111, nom=10000 __MREG__(MAX2837_BIAS_TRIM_CNTRL,8,8,1) // enable BIAS_TRIM_SPI value @@ -255,7 +255,7 @@ __MREG__(MAX2837_SYN_BIAS_TRIM,20,9,2) // 00=max 10=default 11=min /* REG 21 */ __MREG__(MAX2837_SYN_CP_COMMON_MODE_EN,21,0,1) __MREG__(MAX2837_SYN_PRESCALER_BIAS_BOOST,21,1,1) // 0=default 1=+20% -__MREG__(MAX2837_SYN_CP_BETA_EN,21,2,0) +__MREG__(MAX2837_SYN_CP_BETA_EN,21,2,1) __MREG__(MAX2837_SYN_SD_CLOCK_SEL,21,3,1) #define MAX2837_SYN_SD_CLOCK_PFD 0 // from PFD reset #define MAX2837_SYN_SD_CLOCK_PRE 1 // from prescaler From d398cfcc1df723ef2e2bad6e171ccda992805eb9 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Oct 2012 16:58:22 -0700 Subject: [PATCH 06/12] Use new ssp_transfer() function instead of ssp_write(). Implement max2837_spi_read(). --- firmware/common/max2837.c | 7 +++---- firmware/common/max5864.c | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/firmware/common/max2837.c b/firmware/common/max2837.c index 8ad9dadf..464aa8b3 100644 --- a/firmware/common/max2837.c +++ b/firmware/common/max2837.c @@ -121,10 +121,9 @@ void max2837_setup(void) /* SPI register read. */ uint16_t max2837_spi_read(uint8_t r) { gpio_clear(PORT_XCVR_CS, PIN_XCVR_CS); - // FIXME: Unimplemented. - r=r; + const uint16_t value = ssp_transfer(SSP1_NUM, (uint16_t)((1 << 15) | (r << 10))); gpio_set(PORT_XCVR_CS, PIN_XCVR_CS); - return 0; + return value & 0x3ff; } /* SPI register write */ @@ -137,7 +136,7 @@ void max2837_spi_write(uint8_t r, uint16_t v) { LOG("0x%03x -> reg%d\n", v, r); #else gpio_clear(PORT_XCVR_CS, PIN_XCVR_CS); - ssp_write(SSP1_NUM, (uint16_t)((r << 10) | (v & 0x3ff))); + ssp_transfer(SSP1_NUM, (uint16_t)((r << 10) | (v & 0x3ff))); gpio_set(PORT_XCVR_CS, PIN_XCVR_CS); #endif } diff --git a/firmware/common/max5864.c b/firmware/common/max5864.c index a0f5dcff..094ed700 100644 --- a/firmware/common/max5864.c +++ b/firmware/common/max5864.c @@ -29,7 +29,7 @@ void max5864_spi_write(uint_fast8_t value) { gpio_clear(PORT_AD_CS, PIN_AD_CS); - ssp_write(SSP1_NUM, value); + ssp_transfer(SSP1_NUM, value); gpio_set(PORT_AD_CS, PIN_AD_CS); } From 7e34950b24d7e6bb75c03c90883546acbe94ad60 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Oct 2012 17:01:42 -0700 Subject: [PATCH 07/12] Relocate compiler #defines for PACKED, ALIGNED, SECTION. --- firmware/usb_performance/usb.h | 3 --- firmware/usb_performance/usb_type.h | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/firmware/usb_performance/usb.h b/firmware/usb_performance/usb.h index 7b9c9390..a2ab9fb1 100644 --- a/firmware/usb_performance/usb.h +++ b/firmware/usb_performance/usb.h @@ -28,9 +28,6 @@ #include "usb_type.h" -#define ATTR_ALIGNED(x) __attribute__ ((aligned(x))) -#define ATTR_SECTION(x) __attribute__ ((section(x))) - extern bool usb_set_configuration( usb_device_t* const device, const uint_fast8_t configuration_number diff --git a/firmware/usb_performance/usb_type.h b/firmware/usb_performance/usb_type.h index 54287fd5..1bfb3205 100644 --- a/firmware/usb_performance/usb_type.h +++ b/firmware/usb_performance/usb_type.h @@ -25,6 +25,11 @@ #include #include +// TODO: Move this to some common compiler-tricks location. +#define ATTR_PACKED __attribute__((packed)) +#define ATTR_ALIGNED(x) __attribute__ ((aligned(x))) +#define ATTR_SECTION(x) __attribute__ ((section(x))) + typedef struct { uint8_t request_type; uint8_t request; From 048feb131652ad33b322fa9e7a70e06dee05cb1b Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Oct 2012 17:02:55 -0700 Subject: [PATCH 08/12] Miscellaneous USB notes and naming clean-up. --- firmware/usb_performance/usb.h | 2 ++ firmware/usb_performance/usb_request.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/usb_performance/usb.h b/firmware/usb_performance/usb.h index a2ab9fb1..ccaa9184 100644 --- a/firmware/usb_performance/usb.h +++ b/firmware/usb_performance/usb.h @@ -28,6 +28,8 @@ #include "usb_type.h" +// TODO: This is a lame move, requiring an extern to be defined to complete +// the interface between this API and the application. extern bool usb_set_configuration( usb_device_t* const device, const uint_fast8_t configuration_number diff --git a/firmware/usb_performance/usb_request.h b/firmware/usb_performance/usb_request.h index a637924f..2d32bcea 100644 --- a/firmware/usb_performance/usb_request.h +++ b/firmware/usb_performance/usb_request.h @@ -38,7 +38,7 @@ typedef enum { } usb_transfer_stage_t; typedef void (*usb_request_handler_fn)( - usb_endpoint_t* const response, + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage ); From 3c17bad7432c732d5b822cc31c5a041391449fd2 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Oct 2012 17:03:28 -0700 Subject: [PATCH 09/12] Stall USB endpoint if control request is not handled. --- firmware/usb_performance/usb_request.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/firmware/usb_performance/usb_request.c b/firmware/usb_performance/usb_request.c index df6ae427..bfa4ea75 100644 --- a/firmware/usb_performance/usb_request.c +++ b/firmware/usb_performance/usb_request.c @@ -19,6 +19,7 @@ * Boston, MA 02110-1301, USA. */ +#include "usb.h" #include "usb_request.h" #include @@ -49,6 +50,9 @@ static void usb_request( if( handler ) { handler(endpoint, stage); + } else { + // USB 2.0 section 9.2.7 "Request Error" + usb_endpoint_stall(endpoint); } } From f32c6b34caef56e6bc84fbccfb5ce24832baafa7 Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Sat, 13 Oct 2012 17:06:24 -0700 Subject: [PATCH 10/12] Create unions in usb_setup_t so that value, index, and length can be read as words, not just high/low bytes. --- .../usb_performance/usb_standard_request.c | 4 +-- firmware/usb_performance/usb_type.h | 29 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/firmware/usb_performance/usb_standard_request.c b/firmware/usb_performance/usb_standard_request.c index 1b42bd5e..286d783b 100644 --- a/firmware/usb_performance/usb_standard_request.c +++ b/firmware/usb_performance/usb_standard_request.c @@ -67,7 +67,7 @@ static void usb_send_descriptor( usb_endpoint_t* const endpoint, uint8_t* const descriptor_data ) { - const uint32_t setup_length = (endpoint->setup.length_h << 8) | endpoint->setup.length_l; + 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]; @@ -221,7 +221,7 @@ static void usb_standard_request_set_configuration( static void usb_standard_request_get_configuration_setup( usb_endpoint_t* const endpoint ) { - if( (endpoint->setup.length_h == 0) && (endpoint->setup.length_l == 1) ) { + if( endpoint->setup.length == 1 ) { endpoint->buffer[0] = 0; if( endpoint->device->configuration ) { endpoint->buffer[0] = endpoint->device->configuration->number; diff --git a/firmware/usb_performance/usb_type.h b/firmware/usb_performance/usb_type.h index 1bfb3205..fed3172b 100644 --- a/firmware/usb_performance/usb_type.h +++ b/firmware/usb_performance/usb_type.h @@ -30,15 +30,30 @@ #define ATTR_ALIGNED(x) __attribute__ ((aligned(x))) #define ATTR_SECTION(x) __attribute__ ((section(x))) -typedef struct { +typedef struct ATTR_PACKED { uint8_t request_type; uint8_t request; - uint8_t value_l; - uint8_t value_h; - uint8_t index_l; - uint8_t index_h; - uint8_t length_l; - uint8_t length_h; + union { + struct { + uint8_t value_l; + uint8_t value_h; + }; + uint16_t value; + }; + union { + struct { + uint8_t index_l; + uint8_t index_h; + }; + uint16_t index; + }; + union { + struct { + uint8_t length_l; + uint8_t length_h; + }; + uint16_t length; + }; } usb_setup_t; typedef enum { From f64e42dbee452b64da5510c30b4a0221a2f4ebff Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Sat, 13 Oct 2012 21:13:56 -0600 Subject: [PATCH 11/12] updated readme photo from lemondrop/jellybean to jawbreaker --- Readme.md | 5 +++-- doc/jawbreaker.jpeg | Bin 0 -> 444816 bytes 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 doc/jawbreaker.jpeg diff --git a/Readme.md b/Readme.md index ea9e9afe..fa6e199a 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,8 @@ This repository contains hardware designs and software for HackRF, a project to produce a low cost, open source software radio platform. -![Lemondrop and Jellybean](https://github.com/wishi/hackrf/raw/master/doc/lemonAndjelly.jpeg) +![Jawbreaker](https://github.com/wishi/hackrf/raw/master/doc/jawbreaker.jpeg) principal author: Michael Ossmann -source repository: https://github.com/mossmann/hackrf + +http://greatscottgadgets.com/hackrf/ diff --git a/doc/jawbreaker.jpeg b/doc/jawbreaker.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..6d3a8e78fe6285524fc06ec4a7e5ea910833af28 GIT binary patch literal 444816 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