Add software

This commit is contained in:
RocketGod
2022-09-22 09:26:57 -07:00
parent fee0ab05fd
commit 957ea3d712
4511 changed files with 1943182 additions and 0 deletions

View File

@ -0,0 +1,9 @@
*.bin
*.d
*.elf
*.hex
*.list
*.map
*.o
*.srec
*.dfu

View File

@ -0,0 +1,29 @@
# 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.
#
# Top directory CMake project for HackRF firmware
cmake_minimum_required(VERSION 3.1.3)
set(CMAKE_TOOLCHAIN_FILE toolchain-arm-cortex-m.cmake)
project (hackrf_firmware_all C)
add_subdirectory(blinky)
add_subdirectory(hackrf_usb)

View File

@ -0,0 +1,50 @@
The primary firmware source code for USB HackRF devices is hackrf_usb. Most of
the other directories contain firmware source code for test and development.
The common directory contains source code shared by multiple HackRF firmware
projects. The cpld directory contains HDL source for the CPLD.
The firmware is set up for compilation with the GCC toolchain available here:
https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads
Required dependency:
https://github.com/mossmann/libopencm3
If you are using git, the preferred way to install libopencm3 is to use the
submodule:
$ cd ..
$ git submodule init
$ git submodule update
To build and install a standard firmware image for HackRF One:
$ cd hackrf_usb
$ mkdir build
$ cd build
$ cmake ..
$ make
$ hackrf_spiflash -w hackrf_usb.bin
If you have a Jawbreaker, add -DBOARD=JAWBREAKER to the cmake command.
If you have a rad1o, use -DBOARD=RAD1O instead.
It is possible to use a USB Device Firmware Upgrade (DFU) method to load
firmware into RAM. This is normally only required to recover a device that has
had faulty firmware loaded, but it can also be useful for firmware developers.
For loading firmware into RAM with DFU you will need:
http://dfu-util.sourceforge.net/
To start up HackRF One in DFU mode, hold down the DFU button while powering it
on or while pressing and releasing the RESET button. Release the DFU button
after the 3V3 LED illuminates.
A .dfu file is built by default when building firmware. Alternatively you can
use a known good .dfu file from a release package. Load the firmware into RAM
with:
$ dfu-util --device 1fc9:000c --alt 0 --download hackrf_usb.dfu

View File

@ -0,0 +1,14 @@
#!/bin/sh
/usr/bin/env python -m ensurepip
/usr/bin/env python -m pip install pyyaml
cd firmware/libopencm3
export SRCLIBDIR='c:\projects\hackrf\firmware\libopencm3\lib\'
make lib/lpc43xx/m0
make lib/lpc43xx/m4
cd ..
mkdir build-hackrf-one
cd build-hackrf-one
cmake -G "Unix Makefiles" ..
make VERBOSE=1

View File

@ -0,0 +1,33 @@
# 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.
#
cmake_minimum_required(VERSION 3.1.3)
set(CMAKE_TOOLCHAIN_FILE ../toolchain-arm-cortex-m.cmake)
project(blinky C)
include(../hackrf-common.cmake)
set(SRC_M4
blinky.c
)
DeclareTargets()

View File

@ -0,0 +1 @@
This is the simplest example firmware for HackRF. It flashes three LEDs.

View File

@ -0,0 +1,48 @@
/*
* Copyright 2010 - 2012 Michael Ossmann
*
* 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 "hackrf_core.h"
int main(void)
{
pin_setup();
/* enable all power supplies */
enable_1v8_power();
/* Blink LED1/2/3 on the board. */
while (1)
{
led_on(LED1);
led_on(LED2);
led_on(LED3);
delay(2000000);
led_off(LED1);
led_off(LED2);
led_off(LED3);
delay(2000000);
}
return 0;
}

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

@ -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 Rad1o badge - (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 = 128K
ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 128K
ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 64K
ram_sleep (rwx) : ORIGIN = 0x10090000, LENGTH = 8K
}
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
{
.m0_text : {
PROVIDE(__m0_start__ = .);
KEEP(*(.m0_bin*));
. = ALIGN(4);
PROVIDE(__m0_end__ = .);
} >rom
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
MEMORY
{
/* Physical address in Flash used to copy Code from Flash to RAM */
rom_flash (rx) : ORIGIN = 0x80000000, LENGTH = 1M
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)
*/
}
usb_bulk_buffer = ORIGIN(ram_usb);
m0_state = ORIGIN(ram_shared);
PROVIDE(__ram_m0_start__ = ORIGIN(ram_m0));

View File

@ -0,0 +1,2 @@
This directory contains things shared by multiple HackRF firmware
implementations.

View File

@ -0,0 +1,45 @@
/*
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "bitband.h"
volatile uint32_t* peripheral_bitband_address(volatile void* const address, const uint_fast8_t bit_number) {
const uint32_t bit_band_base = 0x42000000;
const uint32_t byte_offset = (uint32_t)address - 0x40000000;
const uint32_t bit_word_offset = (byte_offset * 32) + (bit_number * 4);
const uint32_t bit_word_address = bit_band_base + bit_word_offset;
return (volatile uint32_t*)bit_word_address;
}
void peripheral_bitband_set(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
volatile uint32_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
*bitband_address = 1;
}
void peripheral_bitband_clear(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
volatile uint32_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
*bitband_address = 0;
}
uint32_t peripheral_bitband_get(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
volatile uint32_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
return *bitband_address;
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BITBAND_H__
#define __BITBAND_H__
#include <stdint.h>
volatile uint32_t* peripheral_bitband_address(volatile void* const address, const uint_fast8_t bit_number);
void peripheral_bitband_set(volatile void* const peripheral_address, const uint_fast8_t bit_number);
void peripheral_bitband_clear(volatile void* const peripheral_address, const uint_fast8_t bit_number);
uint32_t peripheral_bitband_get(volatile void* const peripheral_address, const uint_fast8_t bit_number);
#endif//__BITBAND_H__

View File

@ -0,0 +1,4 @@
configure_file(
${SRC}
${DEST}
)

View File

@ -0,0 +1,101 @@
/*
* Copyright 2013 Michael Ossmann <mike@ossmann.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 "cpld_jtag.h"
#include "hackrf_core.h"
#include "xapp058/micro.h"
#include <libopencm3/lpc43xx/scu.h>
#include <stdint.h>
static refill_buffer_cb refill_buffer;
static uint32_t xsvf_buffer_len, xsvf_pos;
static unsigned char* xsvf_buffer;
void cpld_jtag_take(jtag_t* const jtag) {
const jtag_gpio_t* const gpio = jtag->gpio;
/* Set initial GPIO state to the voltages of the internal or external pull-ups/downs,
* to avoid any glitches.
*/
#ifdef HACKRF_ONE
gpio_set(gpio->gpio_pp_tms);
#endif
gpio_set(gpio->gpio_tms);
gpio_set(gpio->gpio_tdi);
gpio_clear(gpio->gpio_tck);
#ifdef HACKRF_ONE
/* Do not drive PortaPack-specific TMS pin initially, just to be cautious. */
gpio_input(gpio->gpio_pp_tms);
gpio_input(gpio->gpio_pp_tdo);
#endif
gpio_output(gpio->gpio_tms);
gpio_output(gpio->gpio_tdi);
gpio_output(gpio->gpio_tck);
gpio_input(gpio->gpio_tdo);
}
void cpld_jtag_release(jtag_t* const jtag) {
const jtag_gpio_t* const gpio = jtag->gpio;
/* Make all pins inputs when JTAG interface not active.
* Let the pull-ups/downs do the work.
*/
#ifdef HACKRF_ONE
/* Do not drive PortaPack-specific pins, initially, just to be cautious. */
gpio_input(gpio->gpio_pp_tms);
gpio_input(gpio->gpio_pp_tdo);
#endif
gpio_input(gpio->gpio_tms);
gpio_input(gpio->gpio_tdi);
gpio_input(gpio->gpio_tck);
gpio_input(gpio->gpio_tdo);
}
/* return 0 if success else return error code see xsvfExecute() */
int cpld_jtag_program(
jtag_t* const jtag,
const uint32_t buffer_length,
unsigned char* const buffer,
refill_buffer_cb refill
) {
int error;
cpld_jtag_take(jtag);
xsvf_buffer = buffer;
xsvf_buffer_len = buffer_length;
refill_buffer = refill;
error = xsvfExecute(jtag->gpio);
cpld_jtag_release(jtag);
return error;
}
/* this gets called by the XAPP058 code */
unsigned char cpld_jtag_get_next_byte(void) {
if (xsvf_pos == xsvf_buffer_len) {
refill_buffer();
xsvf_pos = 0;
}
unsigned char byte = xsvf_buffer[xsvf_pos];
xsvf_pos++;
return byte;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2013 Michael Ossmann <mike@ossmann.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 __CPLD_JTAG_H__
#define __CPLD_JTAG_H__
#include <stdint.h>
#include "gpio.h"
typedef struct jtag_gpio_t {
gpio_t gpio_tms;
gpio_t gpio_tck;
gpio_t gpio_tdi;
gpio_t gpio_tdo;
#ifdef HACKRF_ONE
gpio_t gpio_pp_tms;
gpio_t gpio_pp_tdo;
#endif
} jtag_gpio_t;
typedef struct jtag_t {
jtag_gpio_t* const gpio;
} jtag_t;
typedef void (*refill_buffer_cb)(void);
void cpld_jtag_take(jtag_t* const jtag);
void cpld_jtag_release(jtag_t* const jtag);
/* 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(
jtag_t* const jtag,
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__

View File

@ -0,0 +1,418 @@
/*
* Copyright 2019 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 "cpld_xc2c.h"
#include "crc.h"
#include <stddef.h>
#include <string.h>
typedef enum {
CPLD_XC2C_IR_INTEST = 0b00000010,
CPLD_XC2C_IR_BYPASS = 0b11111111,
CPLD_XC2C_IR_SAMPLE = 0b00000011,
CPLD_XC2C_IR_EXTEST = 0b00000000,
CPLD_XC2C_IR_IDCODE = 0b00000001,
CPLD_XC2C_IR_USERCODE = 0b11111101,
CPLD_XC2C_IR_HIGHZ = 0b11111100,
CPLD_XC2C_IR_ISC_ENABLE_CLAMP = 0b11101001,
CPLD_XC2C_IR_ISC_ENABLE_OTF = 0b11100100,
CPLD_XC2C_IR_ISC_ENABLE = 0b11101000,
CPLD_XC2C_IR_ISC_SRAM_READ = 0b11100111,
CPLD_XC2C_IR_ISC_WRITE = 0b11100110,
CPLD_XC2C_IR_ISC_ERASE = 0b11101101,
CPLD_XC2C_IR_ISC_PROGRAM = 0b11101010,
CPLD_XC2C_IR_ISC_READ = 0b11101110,
CPLD_XC2C_IR_ISC_INIT = 0b11110000,
CPLD_XC2C_IR_ISC_DISABLE = 0b11000000,
CPLD_XC2C_IR_TEST_ENABLE = 0b00010001,
CPLD_XC2C_IR_BULKPROG = 0b00010010,
CPLD_XC2C_IR_ERASE_ALL = 0b00010100,
CPLD_XC2C_IR_MVERIFY = 0b00010011,
CPLD_XC2C_IR_TEST_DISABLE = 0b00010101,
CPLD_XC2C_IR_STCTEST = 0b00010110,
CPLD_XC2C_IR_ISC_NOOP = 0b11100000,
} cpld_xc2c_ir_t;
static bool cpld_xc2c_jtag_clock(const jtag_t* const jtag, const uint32_t tms, const uint32_t tdi) {
// 8 ns TMS/TDI to TCK setup
gpio_write(jtag->gpio->gpio_tdi, tdi);
gpio_write(jtag->gpio->gpio_tms, tms);
// 20 ns TCK high time
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
gpio_clear(jtag->gpio->gpio_tck);
// 25 ns TCK falling edge to TDO valid
// 20 ns TCK low time
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
gpio_set(jtag->gpio->gpio_tck);
// 15 ns TCK to TMS/TDI hold time
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
return gpio_read(jtag->gpio->gpio_tdo);
}
static void cpld_xc2c_jtag_shift_ptr_tms(const jtag_t* const jtag, uint8_t* const tdi_tdo, const size_t start, const size_t end, const bool tms) {
for(size_t i=start; i<end; i++) {
const size_t byte_n = i >> 3;
const size_t bit_n = i & 7;
const uint32_t mask = (1U << bit_n);
const uint32_t tdo = cpld_xc2c_jtag_clock(jtag, tms, tdi_tdo[byte_n] & mask) ? 1 : 0;
tdi_tdo[byte_n] &= ~mask;
tdi_tdo[byte_n] |= (tdo << bit_n);
}
}
static void cpld_xc2c_jtag_shift_ptr(const jtag_t* const jtag, uint8_t* const tdi_tdo, const size_t count) {
if( count > 0 ) {
cpld_xc2c_jtag_shift_ptr_tms(jtag, tdi_tdo, 0, count - 1, false);
cpld_xc2c_jtag_shift_ptr_tms(jtag, tdi_tdo, count - 1, count, true);
}
}
static uint32_t cpld_xc2c_jtag_shift_u32(const jtag_t* const jtag, const uint32_t tms, const uint32_t tdi, const size_t count) {
uint32_t tdo = 0;
for(size_t i=0; i<count; i++) {
const uint32_t mask = (1U << i);
tdo |= cpld_xc2c_jtag_clock(jtag, tms & mask, tdi & mask) << i;
}
return tdo;
}
static void cpld_xc2c_jtag_clocks(const jtag_t* const jtag, const size_t count) {
for(size_t i=0; i<count; i++) {
cpld_xc2c_jtag_clock(jtag, 0, 0);
}
}
static void cpld_xc2c_jtag_pause(const jtag_t* const jtag, const size_t count) {
for(size_t i=0; i<count; i++) {
cpld_xc2c_jtag_clock(jtag, (i == (count - 1)), 0);
}
}
static void cpld_xc2c_jtag_shift_dr_ir(const jtag_t* const jtag, uint8_t* const tdi_tdo, const size_t bit_count, const size_t pause_count) {
/* Run-Test/Idle or Select-DR-Scan -> Shift-DR or Shift-IR */
cpld_xc2c_jtag_shift_u32(jtag, 0b001, 0b000, 3);
/* Shift-[DI]R -> Exit1-[DI]R */
cpld_xc2c_jtag_shift_ptr(jtag, tdi_tdo, bit_count);
if( pause_count ) {
/* Exit1-[DI]R -> Pause-[DI]R */
cpld_xc2c_jtag_shift_u32(jtag, 0b0, 0, 1);
/* Pause-[DI]R -> Exit2-[DI]R */
cpld_xc2c_jtag_pause(jtag, pause_count);
}
/* Exit1-[DI]R or Exit2-[DI]R -> Run-Test/Idle */
cpld_xc2c_jtag_shift_u32(jtag, 0b01, 0, 2);
}
static void cpld_xc2c_jtag_shift_dr(const jtag_t* const jtag, uint8_t* const tdi_tdo, const size_t bit_count, const size_t pause_count) {
cpld_xc2c_jtag_shift_dr_ir(jtag, tdi_tdo, bit_count, pause_count);
}
static uint8_t cpld_xc2c_jtag_shift_ir_pause(const jtag_t* const jtag, const cpld_xc2c_ir_t ir, const size_t pause_count) {
/* Run-Test/Idle -> Select-DR-Scan */
cpld_xc2c_jtag_shift_u32(jtag, 0b1, 0b0, 1);
uint8_t value = ir;
cpld_xc2c_jtag_shift_dr_ir(jtag, &value, 8, pause_count);
return value;
}
static uint8_t cpld_xc2c_jtag_shift_ir(const jtag_t* const jtag, const cpld_xc2c_ir_t ir) {
return cpld_xc2c_jtag_shift_ir_pause(jtag, ir, 0);
}
static void cpld_xc2c_jtag_reset(const jtag_t* const jtag) {
/* Five TMS=1 to reach Test-Logic-Reset from any point in the TAP state diagram.
*/
cpld_xc2c_jtag_shift_u32(jtag, 0b11111, 0, 5);
}
static void cpld_xc2c_jtag_reset_and_idle(const jtag_t* const jtag) {
/* Five TMS=1 to reach Test-Logic-Reset from any point in the TAP state diagram.
* One TMS=0 to move from Test-Logic-Reset to Run-Test-Idle.
*/
cpld_xc2c_jtag_reset(jtag);
cpld_xc2c_jtag_shift_u32(jtag, 0, 0, 1);
}
static uint32_t cpld_xc2c_jtag_idcode(const jtag_t* const jtag) {
/* Enter and end at Run-Test-Idle state. */
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_IDCODE);
uint32_t result = 0;
cpld_xc2c_jtag_shift_dr(jtag, (uint8_t*)&result, 32, 0);
return result;
}
static bool cpld_xc2c64a_jtag_idcode_ok(const jtag_t* const jtag) {
return ((cpld_xc2c_jtag_idcode(jtag) ^ 0xf6e5f093) & 0x0fff8fff) == 0;
}
static void cpld_xc2c_jtag_conld(const jtag_t* const jtag) {
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_DISABLE);
cpld_xc2c_jtag_clocks(jtag, 100);
}
static void cpld_xc2c_jtag_enable(const jtag_t* const jtag) {
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_ENABLE);
cpld_xc2c_jtag_clocks(jtag, 800);
}
static void cpld_xc2c_jtag_disable(const jtag_t* const jtag) {
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_DISABLE);
cpld_xc2c_jtag_clocks(jtag, 100);
}
static void cpld_xc2c_jtag_sram_write(const jtag_t* const jtag) {
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_WRITE);
}
static void cpld_xc2c_jtag_sram_read(const jtag_t* const jtag) {
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_SRAM_READ);
}
static uint32_t cpld_xc2c_jtag_bypass(const jtag_t* const jtag, const bool shift_dr) {
const uint8_t result = cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_BYPASS);
if( shift_dr ) {
uint8_t dr = 0;
cpld_xc2c_jtag_shift_dr(jtag, &dr, 1, 0);
}
return result;
}
static bool cpld_xc2c_jtag_read_write_protect(const jtag_t* const jtag) {
/* Enter and end at Run-Test-Idle state. */
return ((cpld_xc2c_jtag_bypass(jtag, false) ^ 0x01) & 0x03) == 0;
}
static bool cpld_xc2c_jtag_is_done(const jtag_t* const jtag) {
return ((cpld_xc2c_jtag_bypass(jtag, false) ^ 0x05) & 0x07) == 0;
}
static void cpld_xc2c_jtag_init_special(const jtag_t* const jtag) {
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_INIT);
cpld_xc2c_jtag_clocks(jtag, 20);
/* Run-Test/Idle -> Shift-IR */
cpld_xc2c_jtag_shift_u32(jtag, 0b0011, 0b0000, 4);
/* Shift-IR: 0xf0 -> Exit1-IR */
cpld_xc2c_jtag_shift_u32(jtag, 0x80, CPLD_XC2C_IR_ISC_INIT, 8);
/* Exit1-IR -> Pause-IR */
cpld_xc2c_jtag_shift_u32(jtag, 0b0, 0, 1);
/* Pause-IR -> Exit2-IR -> Update-IR -> Select-DR-Scan -> Capture-DR -> Exit1-DR -> Update-DR -> Run-Test/Idle */
cpld_xc2c_jtag_shift_u32(jtag, 0b0110111, 0, 7);
cpld_xc2c_jtag_clocks(jtag, 800);
}
static void cpld_xc2c_jtag_read(const jtag_t* const jtag) {
cpld_xc2c_jtag_shift_ir_pause(jtag, CPLD_XC2C_IR_ISC_READ, 1);
}
static void cpld_xc2c64a_jtag_read_row(const jtag_t* const jtag, uint8_t address, uint8_t* const dr) {
cpld_xc2c_jtag_shift_dr(jtag, &address, 7, 20);
cpld_xc2c_jtag_clocks(jtag, 100);
/* Set array to all ones so we don't transmit memory contents over TDI, and if we're not
* reading a full byte's worth of bits, the excess bits will be zero.
*/
memset(dr, 0xff, CPLD_XC2C64A_BYTES_IN_ROW);
cpld_xc2c_jtag_shift_dr(jtag, dr, CPLD_XC2C64A_BITS_IN_ROW, 0);
cpld_xc2c_jtag_clocks(jtag, 100);
}
bool cpld_xc2c64a_jtag_checksum(
const jtag_t* const jtag,
const cpld_xc2c64a_verify_t* const verify,
uint32_t* const crc_value
) {
cpld_xc2c_jtag_reset_and_idle(jtag);
if( cpld_xc2c64a_jtag_idcode_ok(jtag) && cpld_xc2c_jtag_read_write_protect(jtag) &&
cpld_xc2c64a_jtag_idcode_ok(jtag) && cpld_xc2c_jtag_read_write_protect(jtag) ) {
cpld_xc2c_jtag_bypass(jtag, false);
cpld_xc2c_jtag_enable(jtag);
cpld_xc2c_jtag_enable(jtag);
cpld_xc2c_jtag_enable(jtag);
cpld_xc2c_jtag_read(jtag);
crc32_t crc;
crc32_init(&crc);
uint8_t dr[CPLD_XC2C64A_BYTES_IN_ROW];
for(size_t row=0; row<CPLD_XC2C64A_ROWS; row++) {
const size_t address = cpld_hackrf_row_addresses.address[row];
cpld_xc2c64a_jtag_read_row(jtag, address, dr);
const size_t mask_index = verify->mask_index[row];
for(size_t i=0; i<CPLD_XC2C64A_BYTES_IN_ROW; i++) {
dr[i] &= verify->mask[mask_index].value[i];
}
/* Important checksum calculation NOTE:
* Do checksum of all bits in row bytes, but ensure that invalid bits
* are set to zero by masking. This subtlety just wasted several hours
* of my life...
*/
crc32_update(&crc, dr, CPLD_XC2C64A_BYTES_IN_ROW);
}
*crc_value = crc32_digest(&crc);
cpld_xc2c_jtag_init_special(jtag);
cpld_xc2c_jtag_conld(jtag);
if( cpld_xc2c64a_jtag_idcode_ok(jtag) && cpld_xc2c_jtag_is_done(jtag) ) {
cpld_xc2c_jtag_conld(jtag);
cpld_xc2c_jtag_bypass(jtag, false);
cpld_xc2c_jtag_bypass(jtag, true);
return true;
}
}
cpld_xc2c_jtag_reset_and_idle(jtag);
return false;
}
static void cpld_xc2c64a_jtag_sram_write_row(const jtag_t* const jtag, uint8_t address, const uint8_t* const data) {
uint8_t write[CPLD_XC2C64A_BYTES_IN_ROW];
memcpy(&write[0], data, sizeof(write));
/* Update-IR or Run-Test/Idle -> Shift-DR */
cpld_xc2c_jtag_shift_u32(jtag, 0b001, 0b000, 3);
/* Shift-DR -> Shift-DR */
cpld_xc2c_jtag_shift_ptr_tms(jtag, &write[0], 0, CPLD_XC2C64A_BITS_IN_ROW, false);
/* Shift-DR -> Exit1-DR */
cpld_xc2c_jtag_shift_u32(jtag, 0b1000000, address, 7);
/* Exit1-DR -> Update-DR -> Run-Test/Idle */
cpld_xc2c_jtag_shift_u32(jtag, 0b01, 0b00, 2);
}
static void cpld_xc2c64a_jtag_sram_read_row(const jtag_t* const jtag, uint8_t* const data, const uint8_t next_address) {
/* Run-Test/Idle -> Shift-DR */
cpld_xc2c_jtag_shift_u32(jtag, 0b001, 0b000, 3);
/* Shift-DR */
cpld_xc2c_jtag_shift_ptr_tms(jtag, data, 0, CPLD_XC2C64A_BITS_IN_ROW, false);
/* Shift-DR -> Exit1-DR */
cpld_xc2c_jtag_shift_u32(jtag, 0b1000000, next_address, 7);
/* Weird, non-IEEE1532 compliant path through TAP machine, described in Xilinx
* Programmer Qualification Specification, applicable only to XC2C64/A.
* Exit1-DR -> Pause-DR -> Exit2-DR -> Update-DR -> Run-Test/Idle
*/
cpld_xc2c_jtag_shift_u32(jtag, 0b0110, 0b0000, 4);
}
static bool cpld_xc2c64a_jtag_sram_compare_row(const jtag_t* const jtag, const uint8_t* const expected, const uint8_t* const mask, const uint8_t next_address) {
/* Run-Test/Idle -> Shift-DR */
uint8_t read[CPLD_XC2C64A_BYTES_IN_ROW];
memset(read, 0xff, sizeof(read));
cpld_xc2c64a_jtag_sram_read_row(jtag, &read[0], next_address);
bool matched = true;
if( (expected != NULL) && (mask != NULL) ) {
for(size_t i=0; i<CPLD_XC2C64A_BYTES_IN_ROW; i++) {
const uint8_t significant_differences = (read[i] ^ expected[i]) & mask[i];
matched &= (significant_differences == 0);
}
}
return matched;
}
void cpld_xc2c64a_jtag_sram_write(
const jtag_t* const jtag,
const cpld_xc2c64a_program_t* const program
) {
cpld_xc2c_jtag_reset_and_idle(jtag);
cpld_xc2c_jtag_enable(jtag);
cpld_xc2c_jtag_sram_write(jtag);
for(size_t row=0; row<CPLD_XC2C64A_ROWS; row++) {
const uint8_t address = cpld_hackrf_row_addresses.address[row];
cpld_xc2c64a_jtag_sram_write_row(jtag, address, &program->row[row].data[0]);
}
cpld_xc2c_jtag_disable(jtag);
cpld_xc2c_jtag_bypass(jtag, false);
cpld_xc2c_jtag_reset(jtag);
}
bool cpld_xc2c64a_jtag_sram_verify(
const jtag_t* const jtag,
const cpld_xc2c64a_program_t* const program,
const cpld_xc2c64a_verify_t* const verify
) {
cpld_xc2c_jtag_reset_and_idle(jtag);
cpld_xc2c_jtag_enable(jtag);
cpld_xc2c_jtag_sram_read(jtag);
/* Tricky loop to read dummy row first, then first address, then loop back to get
* the first row's data.
*/
bool matched = true;
for(size_t address_row=0; address_row<=CPLD_XC2C64A_ROWS; address_row++) {
const int data_row = (int)address_row - 1;
const size_t mask_index = (data_row >= 0) ? verify->mask_index[data_row] : 0;
const uint8_t* const expected = (data_row >= 0) ? &program->row[data_row].data[0] : NULL;
const uint8_t* const mask = (data_row >= 0) ? &verify->mask[mask_index].value[0] : NULL;
const uint8_t next_address = (address_row < CPLD_XC2C64A_ROWS) ? cpld_hackrf_row_addresses.address[address_row] : 0;
matched &= cpld_xc2c64a_jtag_sram_compare_row(jtag, expected, mask, next_address);
}
cpld_xc2c_jtag_disable(jtag);
cpld_xc2c_jtag_bypass(jtag, false);
cpld_xc2c_jtag_reset(jtag);
return matched;
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2019 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 __CPLD_XC2C_H__
#define __CPLD_XC2C_H__
#include <stdint.h>
#include <stdbool.h>
#include "cpld_jtag.h"
/* Xilinx CoolRunner II XC2C64A bitstream attributes */
#define CPLD_XC2C64A_ROWS (98)
#define CPLD_XC2C64A_BITS_IN_ROW (274)
#define CPLD_XC2C64A_BYTES_IN_ROW ((CPLD_XC2C64A_BITS_IN_ROW + 7) / 8)
typedef struct {
uint8_t data[CPLD_XC2C64A_BYTES_IN_ROW];
} cpld_xc2c64a_row_data_t;
typedef struct {
cpld_xc2c64a_row_data_t row[CPLD_XC2C64A_ROWS];
} cpld_xc2c64a_program_t;
typedef struct {
uint8_t value[CPLD_XC2C64A_BYTES_IN_ROW];
} cpld_xc2c64a_row_mask_t;
typedef struct {
cpld_xc2c64a_row_mask_t mask[6];
uint8_t mask_index[CPLD_XC2C64A_ROWS];
} cpld_xc2c64a_verify_t;
typedef struct {
uint8_t address[CPLD_XC2C64A_ROWS];
} cpld_xc2c64a_row_addresses_t;
bool cpld_xc2c64a_jtag_checksum(
const jtag_t* const jtag,
const cpld_xc2c64a_verify_t* const verify,
uint32_t* const crc_value
);
void cpld_xc2c64a_jtag_sram_write(
const jtag_t* const jtag,
const cpld_xc2c64a_program_t* const program
);
bool cpld_xc2c64a_jtag_sram_verify(
const jtag_t* const jtag,
const cpld_xc2c64a_program_t* const program,
const cpld_xc2c64a_verify_t* const verify
);
extern const cpld_xc2c64a_program_t cpld_hackrf_program_sram;
extern const cpld_xc2c64a_verify_t cpld_hackrf_verify;
extern const cpld_xc2c64a_row_addresses_t cpld_hackrf_row_addresses;
#endif/*__CPLD_XC2C_H__*/

View File

@ -0,0 +1,49 @@
/*
* Copyright 2019 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 "crc.h"
#include <stdbool.h>
void crc32_init(crc32_t* const crc) {
crc->remainder = 0xffffffff;
crc->reversed_polynomial = 0xedb88320;
crc->final_xor = 0xffffffff;
}
void crc32_update(crc32_t* const crc, const uint8_t* const data, const size_t byte_count) {
uint32_t remainder = crc->remainder;
const size_t bit_count = byte_count * 8;
for(size_t bit_n=0; bit_n<bit_count; bit_n++) {
const bool bit_in = data[bit_n >> 3] & (1 << (bit_n & 7));
remainder ^= (bit_in ? 1 : 0);
const bool bit_out = (remainder & 1);
remainder >>= 1;
if( bit_out ) {
remainder ^= crc->reversed_polynomial;
}
}
crc->remainder = remainder;
}
uint32_t crc32_digest(const crc32_t* const crc) {
return crc->remainder ^ crc->final_xor;
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2019 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 __CRC_H__
#define __CRC_H__
#include <stdint.h>
#include <stddef.h>
typedef struct {
uint32_t remainder;
uint32_t reversed_polynomial;
uint32_t final_xor;
} crc32_t;
void crc32_init(crc32_t* const crc);
void crc32_update(crc32_t* const crc, const uint8_t* const data, const size_t byte_count);
uint32_t crc32_digest(const crc32_t* const crc);
#endif//__CRC_H__

View File

@ -0,0 +1,86 @@
/*
* Copyright 2012 Jared Boone <jared@sharebrained.com>
* 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.
*/
#include <stdint.h>
#include "fault_handler.h"
typedef struct
{
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr; /* Link Register. */
uint32_t pc; /* Program Counter. */
uint32_t psr;/* Program Status Register. */
} hard_fault_stack_t;
__attribute__((naked))
void hard_fault_handler(void) {
__asm__("TST LR, #4");
__asm__("ITE EQ");
__asm__("MRSEQ R0, MSP");
__asm__("MRSNE R0, PSP");
__asm__("B hard_fault_handler_c");
}
volatile hard_fault_stack_t* hard_fault_stack_pt;
__attribute__((used)) void hard_fault_handler_c(uint32_t* args)
{
/* hard_fault_stack_pt contains registers saved before the hard fault */
hard_fault_stack_pt = (hard_fault_stack_t*)args;
// args[0-7]: r0, r1, r2, r3, r12, lr, pc, psr
// Other interesting registers to examine:
// CFSR: Configurable Fault Status Register
// HFSR: Hard Fault Status Register
// DFSR: Debug Fault Status Register
// AFSR: Auxiliary Fault Status Register
// MMAR: MemManage Fault Address Register
// BFAR: Bus Fault Address Register
/*
if( SCB->HFSR & SCB_HFSR_FORCED ) {
if( SCB->CFSR & SCB_CFSR_BFSR_BFARVALID ) {
SCB->BFAR;
if( SCB->CFSR & CSCB_CFSR_BFSR_PRECISERR ) {
}
}
}
*/
while(1);
}
void mem_manage_handler() {
while(1);
}
void bus_fault_handler() {
while(1);
}
void usage_fault_handler() {
while(1);
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __FAULT_HANDLER__
#define __FAULT_HANDLER__
#include <stdint.h>
#include <libopencm3/cm3/memorymap.h>
// TODO: Move all this to a Cortex-M(?) include file, since these
// structures are supposedly the same between processors (to an
// undetermined extent).
typedef struct armv7m_scb_t armv7m_scb_t;
struct armv7m_scb_t {
volatile const uint32_t CPUID;
volatile uint32_t ICSR;
volatile uint32_t VTOR;
volatile uint32_t AIRCR;
volatile uint32_t SCR;
volatile uint32_t CCR;
volatile uint32_t SHPR1;
volatile uint32_t SHPR2;
volatile uint32_t SHPR3;
volatile uint32_t SHCSR;
volatile uint32_t CFSR;
volatile uint32_t HFSR;
volatile uint32_t DFSR;
volatile uint32_t MMFAR;
volatile uint32_t BFAR;
volatile uint32_t AFSR;
volatile const uint32_t ID_PFR0;
volatile const uint32_t ID_PFR1;
volatile const uint32_t ID_DFR0;
volatile const uint32_t ID_AFR0;
volatile const uint32_t ID_MMFR0;
volatile const uint32_t ID_MMFR1;
volatile const uint32_t ID_MMFR2;
volatile const uint32_t ID_MMFR3;
volatile const uint32_t ID_ISAR0;
volatile const uint32_t ID_ISAR1;
volatile const uint32_t ID_ISAR2;
volatile const uint32_t ID_ISAR3;
volatile const uint32_t ID_ISAR4;
volatile const uint32_t __reserved_0x74_0x87[5];
volatile uint32_t CPACR;
} __attribute__((packed));
static armv7m_scb_t* const SCB = (armv7m_scb_t*)SCB_BASE;
#define SCB_HFSR_DEBUGEVT (1 << 31)
#define SCB_HFSR_FORCED (1 << 30)
#define SCB_HFSR_VECTTBL (1 << 1)
#endif//__FAULT_HANDLER__

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;
}

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

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 __GPIO_H__
#define __GPIO_H__
#include <stdbool.h>
typedef const struct gpio_t* gpio_t;
void gpio_init();
void gpio_set(gpio_t gpio);
void gpio_clear(gpio_t gpio);
void gpio_toggle(gpio_t gpio);
void gpio_output(gpio_t gpio);
void gpio_input(gpio_t gpio);
void gpio_write(gpio_t gpio, const bool value);
bool gpio_read(gpio_t gpio);
#endif/*__GPIO_H__*/

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 "gpio_lpc.h"
#include <stddef.h>
void gpio_init() {
for(size_t i=0; i<8; i++) {
GPIO_LPC_PORT(i)->dir = 0;
}
}
void gpio_set(gpio_t gpio) {
gpio->port->set = gpio->mask;
}
void gpio_clear(gpio_t gpio) {
gpio->port->clr = gpio->mask;
}
void gpio_toggle(gpio_t gpio) {
gpio->port->not = gpio->mask;
}
void gpio_output(gpio_t gpio) {
gpio->port->dir |= gpio->mask;
}
void gpio_input(gpio_t gpio) {
gpio->port->dir &= ~gpio->mask;
}
void gpio_write(gpio_t gpio, const bool value) {
*gpio->gpio_w = value;
}
bool gpio_read(gpio_t gpio) {
return *gpio->gpio_w;
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 __GPIO_LPC_H__
#define __GPIO_LPC_H__
#include <stdint.h>
#include "gpio.h"
/* NOTE: libopencm3 constants and functions not used here due to naming
* conflicts. I'd recommend changes to libopencm3 design to separate
* register #defines and API declarations into separate header files.
*/
typedef struct gpio_port_t {
volatile uint32_t dir; /* +0x000 */
uint32_t _reserved0[31];
volatile uint32_t mask; /* +0x080 */
uint32_t _reserved1[31];
volatile uint32_t pin; /* +0x100 */
uint32_t _reserved2[31];
volatile uint32_t mpin; /* +0x180 */
uint32_t _reserved3[31];
volatile uint32_t set; /* +0x200 */
uint32_t _reserved4[31];
volatile uint32_t clr; /* +0x280 */
uint32_t _reserved5[31];
volatile uint32_t not; /* +0x300 */
} gpio_port_t;
struct gpio_t {
const uint32_t mask;
gpio_port_t* const port;
volatile uint32_t* const gpio_w;
};
#define GPIO_LPC_BASE (0x400f4000)
#define GPIO_LPC_B_OFFSET (0x0)
#define GPIO_LPC_W_OFFSET (0x1000)
#define GPIO_LPC_PORT_OFFSET (0x2000)
#define GPIO_LPC_PORT(_n) ((gpio_port_t*)((GPIO_LPC_BASE + GPIO_LPC_PORT_OFFSET) + (_n) * 4))
#define GPIO_LPC_W(_port_num, _pin_num) (volatile uint32_t*)((GPIO_LPC_BASE + GPIO_LPC_W_OFFSET) + ((_port_num) * 0x80) + ((_pin_num) * 4))
#define GPIO(_port_num, _pin_num) { \
.mask = (1UL << (_pin_num)), \
.port = GPIO_LPC_PORT(_port_num), \
.gpio_w = GPIO_LPC_W(_port_num, _pin_num), \
}
#endif/*__GPIO_LPC_H__*/

View File

@ -0,0 +1,930 @@
/*
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
* Copyright 2012 Jared Boone <jared@sharebrained.com>
* 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.
*/
#include "hackrf_core.h"
#include "hackrf_ui.h"
#include "sgpio.h"
#include "si5351c.h"
#include "spi_ssp.h"
#include "max2837.h"
#include "max2837_target.h"
#include "max5864.h"
#include "max5864_target.h"
#include "w25q80bv.h"
#include "w25q80bv_target.h"
#include "i2c_bus.h"
#include "i2c_lpc.h"
#include "cpld_jtag.h"
#include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/lpc43xx/ccu.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/ssp.h>
#ifdef HACKRF_ONE
#include "portapack.h"
#endif
#include "gpio_lpc.h"
#define WAIT_CPU_CLOCK_INIT_DELAY (10000)
/* GPIO Output PinMux */
static struct gpio_t gpio_led[] = {
GPIO(2, 1),
GPIO(2, 2),
GPIO(2, 8),
#ifdef RAD1O
GPIO(5, 26),
#endif
};
static struct gpio_t gpio_1v8_enable = GPIO(3, 6);
/* MAX2837 GPIO (XCVR_CTL) PinMux */
static struct gpio_t gpio_max2837_select = GPIO(0, 15);
static struct gpio_t gpio_max2837_enable = GPIO(2, 6);
static struct gpio_t gpio_max2837_rx_enable = GPIO(2, 5);
static struct gpio_t gpio_max2837_tx_enable = GPIO(2, 4);
/* MAX5864 SPI chip select (AD_CS) GPIO PinMux */
static struct gpio_t gpio_max5864_select = GPIO(2, 7);
/* RFFC5071 GPIO serial interface PinMux */
// #ifdef RAD1O
// static struct gpio_t gpio_rffc5072_select = GPIO(2, 13);
// static struct gpio_t gpio_rffc5072_clock = GPIO(5, 6);
// static struct gpio_t gpio_rffc5072_data = GPIO(3, 3);
// static struct gpio_t gpio_rffc5072_reset = GPIO(2, 14);
// #endif
/* RF supply (VAA) control */
#ifdef HACKRF_ONE
static struct gpio_t gpio_vaa_disable = GPIO(2, 9);
#endif
#ifdef RAD1O
static struct gpio_t gpio_vaa_enable = GPIO(2, 9);
#endif
static struct gpio_t gpio_w25q80bv_hold = GPIO(1, 14);
static struct gpio_t gpio_w25q80bv_wp = GPIO(1, 15);
static struct gpio_t gpio_w25q80bv_select = GPIO(5, 11);
/* RF switch control */
#ifdef HACKRF_ONE
static struct gpio_t gpio_hp = GPIO(2, 0);
static struct gpio_t gpio_lp = GPIO(2, 10);
static struct gpio_t gpio_tx_mix_bp = GPIO(2, 11);
static struct gpio_t gpio_no_mix_bypass = GPIO(1, 0);
static struct gpio_t gpio_rx_mix_bp = GPIO(2, 12);
static struct gpio_t gpio_tx_amp = GPIO(2, 15);
static struct gpio_t gpio_tx = GPIO(5, 15);
static struct gpio_t gpio_mix_bypass = GPIO(5, 16);
static struct gpio_t gpio_rx = GPIO(5, 5);
static struct gpio_t gpio_no_tx_amp_pwr = GPIO(3, 5);
static struct gpio_t gpio_amp_bypass = GPIO(0, 14);
static struct gpio_t gpio_rx_amp = GPIO(1, 11);
static struct gpio_t gpio_no_rx_amp_pwr = GPIO(1, 12);
#endif
#ifdef RAD1O
static struct gpio_t gpio_tx_rx_n = GPIO(1, 11);
static struct gpio_t gpio_tx_rx = GPIO(0, 14);
static struct gpio_t gpio_by_mix = GPIO(1, 12);
static struct gpio_t gpio_by_mix_n = GPIO(2, 10);
static struct gpio_t gpio_by_amp = GPIO(1, 0);
static struct gpio_t gpio_by_amp_n = GPIO(5, 5);
static struct gpio_t gpio_mixer_en = GPIO(5, 16);
static struct gpio_t gpio_low_high_filt = GPIO(2, 11);
static struct gpio_t gpio_low_high_filt_n = GPIO(2, 12);
static struct gpio_t gpio_tx_amp = GPIO(2, 15);
static struct gpio_t gpio_rx_lna = GPIO(5, 15);
#endif
/* CPLD JTAG interface GPIO pins */
static struct gpio_t gpio_cpld_tdo = GPIO(5, 18);
static struct gpio_t gpio_cpld_tck = GPIO(3, 0);
#if (defined HACKRF_ONE || defined RAD1O)
static struct gpio_t gpio_cpld_tms = GPIO(3, 4);
static struct gpio_t gpio_cpld_tdi = GPIO(3, 1);
#else
static struct gpio_t gpio_cpld_tms = GPIO(3, 1);
static struct gpio_t gpio_cpld_tdi = GPIO(3, 4);
#endif
#ifdef HACKRF_ONE
static struct gpio_t gpio_cpld_pp_tms = GPIO(1, 1);
static struct gpio_t gpio_cpld_pp_tdo = GPIO(1, 8);
#endif
static struct gpio_t gpio_hw_sync_enable = GPIO(5,12);
static struct gpio_t gpio_rx_q_invert = GPIO(0, 13);
i2c_bus_t i2c0 = {
.obj = (void*)I2C0_BASE,
.start = i2c_lpc_start,
.stop = i2c_lpc_stop,
.transfer = i2c_lpc_transfer,
};
i2c_bus_t i2c1 = {
.obj = (void*)I2C1_BASE,
.start = i2c_lpc_start,
.stop = i2c_lpc_stop,
.transfer = i2c_lpc_transfer,
};
// const i2c_lpc_config_t i2c_config_si5351c_slow_clock = {
// .duty_cycle_count = 15,
// };
const i2c_lpc_config_t i2c_config_si5351c_fast_clock = {
.duty_cycle_count = 255,
};
si5351c_driver_t clock_gen = {
.bus = &i2c0,
.i2c_address = 0x60,
};
const ssp_config_t ssp_config_max2837 = {
/* FIXME speed up once everything is working reliably */
/*
// Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz
const uint8_t serial_clock_rate = 32;
const uint8_t clock_prescale_rate = 128;
*/
// Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz
.data_bits = SSP_DATA_16BITS,
.serial_clock_rate = 21,
.clock_prescale_rate = 2,
.gpio_select = &gpio_max2837_select,
};
const ssp_config_t ssp_config_max5864 = {
/* FIXME speed up once everything is working reliably */
/*
// Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz
const uint8_t serial_clock_rate = 32;
const uint8_t clock_prescale_rate = 128;
*/
// Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz
.data_bits = SSP_DATA_8BITS,
.serial_clock_rate = 21,
.clock_prescale_rate = 2,
.gpio_select = &gpio_max5864_select,
};
spi_bus_t spi_bus_ssp1 = {
.obj = (void*)SSP1_BASE,
.config = &ssp_config_max2837,
.start = spi_ssp_start,
.stop = spi_ssp_stop,
.transfer = spi_ssp_transfer,
.transfer_gather = spi_ssp_transfer_gather,
};
max2837_driver_t max2837 = {
.bus = &spi_bus_ssp1,
.gpio_enable = &gpio_max2837_enable,
.gpio_rx_enable = &gpio_max2837_rx_enable,
.gpio_tx_enable = &gpio_max2837_tx_enable,
.target_init = max2837_target_init,
.set_mode = max2837_target_set_mode,
};
max5864_driver_t max5864 = {
.bus = &spi_bus_ssp1,
.target_init = max5864_target_init,
};
const ssp_config_t ssp_config_w25q80bv = {
.data_bits = SSP_DATA_8BITS,
.serial_clock_rate = 2,
.clock_prescale_rate = 2,
.gpio_select = &gpio_w25q80bv_select,
};
spi_bus_t spi_bus_ssp0 = {
.obj = (void*)SSP0_BASE,
.config = &ssp_config_w25q80bv,
.start = spi_ssp_start,
.stop = spi_ssp_stop,
.transfer = spi_ssp_transfer,
.transfer_gather = spi_ssp_transfer_gather,
};
w25q80bv_driver_t spi_flash = {
.bus = &spi_bus_ssp0,
.gpio_hold = &gpio_w25q80bv_hold,
.gpio_wp = &gpio_w25q80bv_wp,
.target_init = w25q80bv_target_init,
};
sgpio_config_t sgpio_config = {
.gpio_rx_q_invert = &gpio_rx_q_invert,
.gpio_hw_sync_enable = &gpio_hw_sync_enable,
.slice_mode_multislice = true,
};
rf_path_t rf_path = {
.switchctrl = 0,
#ifdef HACKRF_ONE
.gpio_hp = &gpio_hp,
.gpio_lp = &gpio_lp,
.gpio_tx_mix_bp = &gpio_tx_mix_bp,
.gpio_no_mix_bypass = &gpio_no_mix_bypass,
.gpio_rx_mix_bp = &gpio_rx_mix_bp,
.gpio_tx_amp = &gpio_tx_amp,
.gpio_tx = &gpio_tx,
.gpio_mix_bypass = &gpio_mix_bypass,
.gpio_rx = &gpio_rx,
.gpio_no_tx_amp_pwr = &gpio_no_tx_amp_pwr,
.gpio_amp_bypass = &gpio_amp_bypass,
.gpio_rx_amp = &gpio_rx_amp,
.gpio_no_rx_amp_pwr = &gpio_no_rx_amp_pwr,
#endif
#ifdef RAD1O
.gpio_tx_rx_n = &gpio_tx_rx_n,
.gpio_tx_rx = &gpio_tx_rx,
.gpio_by_mix = &gpio_by_mix,
.gpio_by_mix_n = &gpio_by_mix_n,
.gpio_by_amp = &gpio_by_amp,
.gpio_by_amp_n = &gpio_by_amp_n,
.gpio_mixer_en = &gpio_mixer_en,
.gpio_low_high_filt = &gpio_low_high_filt,
.gpio_low_high_filt_n = &gpio_low_high_filt_n,
.gpio_tx_amp = &gpio_tx_amp,
.gpio_rx_lna = &gpio_rx_lna,
#endif
};
jtag_gpio_t jtag_gpio_cpld = {
.gpio_tms = &gpio_cpld_tms,
.gpio_tck = &gpio_cpld_tck,
.gpio_tdi = &gpio_cpld_tdi,
.gpio_tdo = &gpio_cpld_tdo,
#ifdef HACKRF_ONE
.gpio_pp_tms = &gpio_cpld_pp_tms,
.gpio_pp_tdo = &gpio_cpld_pp_tdo,
#endif
};
jtag_t jtag_cpld = {
.gpio = &jtag_gpio_cpld,
};
void delay(uint32_t duration)
{
uint32_t i;
for (i = 0; i < duration; i++)
__asm__("nop");
}
/* GCD algo from wikipedia */
/* http://en.wikipedia.org/wiki/Greatest_common_divisor */
static uint32_t
gcd(uint32_t u, uint32_t v)
{
int s;
if (!u || !v)
return u | v;
for (s=0; !((u|v)&1); s++) {
u >>= 1;
v >>= 1;
}
while (!(u&1))
u >>= 1;
do {
while (!(v&1))
v >>= 1;
if (u>v) {
uint32_t t;
t = v;
v = u;
u = t;
}
v = v - u;
}
while (v);
return u << s;
}
bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
{
const uint64_t VCO_FREQ = 800 * 1000 * 1000; /* 800 MHz */
uint32_t MSx_P1,MSx_P2,MSx_P3;
uint32_t a, b, c;
uint32_t rem;
hackrf_ui()->set_sample_rate(rate_num/2);
/* Find best config */
a = (VCO_FREQ * rate_denom) / rate_num;
rem = (VCO_FREQ * rate_denom) - (a * rate_num);
if (!rem) {
/* Integer mode */
b = 0;
c = 1;
} else {
/* Fractional */
uint32_t g = gcd(rem, rate_num);
rem /= g;
rate_num /= g;
if (rate_num < (1<<20)) {
/* Perfect match */
b = rem;
c = rate_num;
} else {
/* Approximate */
c = (1<<20) - 1;
b = ((uint64_t)c * (uint64_t)rem) / rate_num;
g = gcd(b, c);
b /= g;
c /= g;
}
}
bool streaming = sgpio_cpld_stream_is_enabled(&sgpio_config);
if (streaming) {
sgpio_cpld_stream_disable(&sgpio_config);
}
/* Can we enable integer mode ? */
if (a & 0x1 || b)
si5351c_set_int_mode(&clock_gen, 0, 0);
else
si5351c_set_int_mode(&clock_gen, 0, 1);
/* Final MS values */
MSx_P1 = 128*a + (128 * b/c) - 512;
MSx_P2 = (128*b) % c;
MSx_P3 = c;
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0);//p1 doesn't matter
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0);//p1 doesn't matter
if (streaming) {
sgpio_cpld_stream_enable(&sgpio_config);
}
return true;
}
bool sample_rate_set(const uint32_t sample_rate_hz) {
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;
case 16000000:
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;
default:
return false;
}
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(&clock_gen, 1, p1, 0, 1, 0);//p1 doesn't matter
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(&clock_gen, 2, p1, 0, 1, 0);//p1 doesn't matter
return true;
}
bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) {
uint32_t bandwidth_hz_real = max2837_set_lpf_bandwidth(&max2837, bandwidth_hz);
if(bandwidth_hz_real) hackrf_ui()->set_filter_bw(bandwidth_hz_real);
return bandwidth_hz_real != 0;
}
/*
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().
*/
static 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));
/* use PLL1 as clock source for BASE_M4_CLK (CPU) */
CGU_BASE_M4_CLK = (CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1) | CGU_BASE_M4_CLK_AUTOBLOCK(1));
/* 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));
}
/* clock startup for LPC4320 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) */
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_IRC);
/* use IRC as clock source for APB3 */
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC);
i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock);
si5351c_disable_all_outputs(&clock_gen);
si5351c_disable_oeb_pin_control(&clock_gen);
si5351c_power_down_all_clocks(&clock_gen);
si5351c_set_crystal_configuration(&clock_gen);
si5351c_enable_xo_and_ms_fanout(&clock_gen);
si5351c_configure_pll_sources(&clock_gen);
si5351c_configure_pll_multisynth(&clock_gen);
/*
* Clocks:
* CLK0 -> MAX5864/CPLD
* CLK1 -> CPLD
* CLK2 -> SGPIO
* CLK3 -> External Clock Output (power down at boot)
* CLK4 -> RFFC5072 (MAX2837 on rad1o)
* CLK5 -> MAX2837 (MAX2871 on rad1o)
* CLK6 -> none
* CLK7 -> LPC43xx (uses a 12MHz crystal by default)
*/
/* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */
si5351c_configure_multisynth(&clock_gen, 4, 20*128-512, 0, 1, 0); /* 800/20 = 40MHz */
/* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */
si5351c_configure_multisynth(&clock_gen, 5, 20*128-512, 0, 1, 0); /* 800/20 = 40MHz */
/* MS6/CLK6 is unused. */
/* MS7/CLK7 is unused. */
/* Set to 10 MHz, the common rate between Jawbreaker and HackRF One. */
sample_rate_set(10000000);
si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL);
// soft reset
si5351c_reset_pll(&clock_gen);
si5351c_enable_clock_outputs(&clock_gen);
//FIXME disable I2C
/* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */
i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock);
/*
* 12MHz clock is entering LPC XTAL1/OSC input now.
* On HackRF One and Jawbreaker, there is a 12 MHz crystal at the LPC.
* Set up PLL1 to run from XTAL1 input.
*/
//FIXME a lot of the details here should be in a CGU driver
/* set xtal oscillator to low frequency mode */
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_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_AUTOBLOCK(1));
/* use XTAL_OSC as clock source for APB1 */
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 APB3 */
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_AUTOBLOCK(1)
| CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL);
cpu_clock_pll1_max_speed();
/* use XTAL_OSC as clock source for PLL0USB */
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_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(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_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(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(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(1)
| CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1);
/* Switch APB3 clock over to use PLL1 (204MHz) */
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_AUTOBLOCK(1)
| CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1);
CGU_BASE_SSP0_CLK = CGU_BASE_SSP0_CLK_AUTOBLOCK(1)
| CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1);
CGU_BASE_SSP1_CLK = CGU_BASE_SSP1_CLK_AUTOBLOCK(1)
| CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1);
#if (defined JAWBREAKER || defined HACKRF_ONE)
/* Disable unused clocks */
/* Start with PLLs */
CGU_PLL0AUDIO_CTRL = CGU_PLL0AUDIO_CTRL_PD(1);
/* Dividers */
CGU_IDIVA_CTRL = CGU_IDIVA_CTRL_PD(1);
CGU_IDIVB_CTRL = CGU_IDIVB_CTRL_PD(1);
CGU_IDIVC_CTRL = CGU_IDIVC_CTRL_PD(1);
CGU_IDIVD_CTRL = CGU_IDIVD_CTRL_PD(1);
CGU_IDIVE_CTRL = CGU_IDIVE_CTRL_PD(1);
/* Base clocks */
CGU_BASE_SPIFI_CLK = CGU_BASE_SPIFI_CLK_PD(1); /* SPIFI is only used at boot */
CGU_BASE_USB1_CLK = CGU_BASE_USB1_CLK_PD(1); /* USB1 is not exposed on HackRF */
CGU_BASE_PHY_RX_CLK = CGU_BASE_PHY_RX_CLK_PD(1);
CGU_BASE_PHY_TX_CLK = CGU_BASE_PHY_TX_CLK_PD(1);
CGU_BASE_LCD_CLK = CGU_BASE_LCD_CLK_PD(1);
CGU_BASE_VADC_CLK = CGU_BASE_VADC_CLK_PD(1);
CGU_BASE_SDIO_CLK = CGU_BASE_SDIO_CLK_PD(1);
CGU_BASE_UART0_CLK = CGU_BASE_UART0_CLK_PD(1);
CGU_BASE_UART1_CLK = CGU_BASE_UART1_CLK_PD(1);
CGU_BASE_UART2_CLK = CGU_BASE_UART2_CLK_PD(1);
CGU_BASE_UART3_CLK = CGU_BASE_UART3_CLK_PD(1);
CGU_BASE_OUT_CLK = CGU_BASE_OUT_CLK_PD(1);
CGU_BASE_AUDIO_CLK = CGU_BASE_AUDIO_CLK_PD(1);
CGU_BASE_CGU_OUT0_CLK = CGU_BASE_CGU_OUT0_CLK_PD(1);
CGU_BASE_CGU_OUT1_CLK = CGU_BASE_CGU_OUT1_CLK_PD(1);
/* Disable unused peripheral clocks */
CCU1_CLK_APB1_CAN1_CFG = 0;
CCU1_CLK_APB1_I2S_CFG = 0;
CCU1_CLK_APB1_MOTOCONPWM_CFG = 0;
CCU1_CLK_APB3_ADC0_CFG = 0;
CCU1_CLK_APB3_ADC1_CFG = 0;
CCU1_CLK_APB3_CAN0_CFG = 0;
CCU1_CLK_APB3_DAC_CFG = 0;
CCU1_CLK_M4_DMA_CFG = 0;
CCU1_CLK_M4_EMC_CFG = 0;
CCU1_CLK_M4_EMCDIV_CFG = 0;
CCU1_CLK_M4_ETHERNET_CFG = 0;
CCU1_CLK_M4_LCD_CFG = 0;
CCU1_CLK_M4_QEI_CFG = 0;
CCU1_CLK_M4_RITIMER_CFG = 0;
// CCU1_CLK_M4_SCT_CFG = 0;
CCU1_CLK_M4_SDIO_CFG = 0;
CCU1_CLK_M4_SPIFI_CFG = 0;
CCU1_CLK_M4_TIMER0_CFG = 0;
CCU1_CLK_M4_TIMER1_CFG = 0;
CCU1_CLK_M4_TIMER2_CFG = 0;
CCU1_CLK_M4_TIMER3_CFG = 0;
CCU1_CLK_M4_UART1_CFG = 0;
CCU1_CLK_M4_USART0_CFG = 0;
CCU1_CLK_M4_USART2_CFG = 0;
CCU1_CLK_M4_USART3_CFG = 0;
CCU1_CLK_M4_USB1_CFG = 0;
CCU1_CLK_M4_VADC_CFG = 0;
// CCU1_CLK_SPIFI_CFG = 0;
// CCU1_CLK_USB1_CFG = 0;
// CCU1_CLK_VADC_CFG = 0;
// CCU2_CLK_APB0_UART1_CFG = 0;
// CCU2_CLK_APB0_USART0_CFG = 0;
// CCU2_CLK_APB2_USART2_CFG = 0;
// CCU2_CLK_APB2_USART3_CFG = 0;
// CCU2_CLK_APLL_CFG = 0;
// CCU2_CLK_SDIO_CFG = 0;
#endif
}
clock_source_t activate_best_clock_source(void)
{
#ifdef HACKRF_ONE
/* Ensure PortaPack reference oscillator is off while checking for external clock input. */
if( portapack_reference_oscillator && portapack()) {
portapack_reference_oscillator(false);
}
#endif
clock_source_t source = CLOCK_SOURCE_HACKRF;
/* Check for external clock input. */
if (si5351c_clkin_signal_valid(&clock_gen)) {
source = CLOCK_SOURCE_EXTERNAL;
} else {
#ifdef HACKRF_ONE
/* Enable PortaPack reference oscillator (if present), and check for valid clock. */
if( portapack_reference_oscillator && portapack() ) {
portapack_reference_oscillator(true);
delay(510000); /* loop iterations @ 204MHz for >10ms for oscillator to enable. */
if (si5351c_clkin_signal_valid(&clock_gen)) {
source = CLOCK_SOURCE_PORTAPACK;
} else {
portapack_reference_oscillator(false);
}
}
#endif
/* No external or PortaPack clock was found. Use HackRF Si5351C crystal. */
}
si5351c_set_clock_source(&clock_gen, (source == CLOCK_SOURCE_HACKRF) ? PLL_SOURCE_XTAL : PLL_SOURCE_CLKIN);
hackrf_ui()->set_clock_source(source);
return source;
}
void ssp1_set_mode_max2837(void)
{
spi_bus_start(max2837.bus, &ssp_config_max2837);
}
void ssp1_set_mode_max5864(void)
{
spi_bus_start(max5864.bus, &ssp_config_max5864);
}
void pin_setup(void) {
/* Configure all GPIO as Input (safe state) */
gpio_init();
/* TDI and TMS pull-ups are required in all JTAG-compliant devices.
*
* The HackRF CPLD is always present, so let the CPLD pull up its TDI and TMS.
*
* The PortaPack may not be present, so pull up the PortaPack TMS pin from the
* microcontroller.
*
* TCK is recommended to be held low, so use microcontroller pull-down.
*
* TDO is undriven except when in Shift-IR or Shift-DR phases.
* Use the microcontroller to pull down to keep from floating.
*
* LPC43xx pull-up and pull-down resistors are approximately 53K.
*/
#ifdef HACKRF_ONE
scu_pinmux(SCU_PINMUX_PP_TMS, SCU_GPIO_PUP | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_PP_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
#endif
scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_PDN | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
/* Configure SCU Pin Mux as GPIO */
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_NOPULL);
#ifdef RAD1O
scu_pinmux(SCU_PINMUX_LED4, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4);
#endif
/* Configure USB indicators */
#ifdef JAWBREAKER
scu_pinmux(SCU_PINMUX_USB_LED0, SCU_CONF_FUNCTION3);
scu_pinmux(SCU_PINMUX_USB_LED1, SCU_CONF_FUNCTION3);
#endif
gpio_output(&gpio_led[0]);
gpio_output(&gpio_led[1]);
gpio_output(&gpio_led[2]);
#ifdef RAD1O
gpio_output(&gpio_led[3]);
#endif
disable_1v8_power();
gpio_output(&gpio_1v8_enable);
scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
#ifdef HACKRF_ONE
/* Safe state: start with VAA turned off: */
disable_rf_power();
/* Configure RF power supply (VAA) switch control signal as output */
gpio_output(&gpio_vaa_disable);
#endif
#ifdef RAD1O
/* Safe state: start with VAA turned off: */
disable_rf_power();
/* Configure RF power supply (VAA) switch control signal as output */
gpio_output(&gpio_vaa_enable);
/* Disable unused clock outputs. They generate noise. */
scu_pinmux(CLK0, SCU_CLK_IN | SCU_CONF_FUNCTION7);
scu_pinmux(CLK2, SCU_CLK_IN | SCU_CONF_FUNCTION7);
scu_pinmux(SCU_PINMUX_GPIO3_10, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_GPIO3_11, SCU_GPIO_PDN | SCU_CONF_FUNCTION0);
#endif
/* enable input on SCL and SDA pins */
SCU_SFSI2C0 = SCU_I2C0_NOMINAL;
spi_bus_start(&spi_bus_ssp1, &ssp_config_max2837);
mixer_bus_setup(&mixer);
rf_path_pin_setup(&rf_path);
/* Configure external clock in */
scu_pinmux(SCU_PINMUX_GP_CLKIN, SCU_CLK_IN | SCU_CONF_FUNCTION1);
sgpio_configure_pin_functions(&sgpio_config);
}
void enable_1v8_power(void) {
gpio_set(&gpio_1v8_enable);
}
void disable_1v8_power(void) {
gpio_clear(&gpio_1v8_enable);
}
#ifdef HACKRF_ONE
void enable_rf_power(void) {
uint32_t i;
/* many short pulses to avoid one big voltage glitch */
for (i = 0; i < 1000; i++) {
gpio_clear(&gpio_vaa_disable);
gpio_set(&gpio_vaa_disable);
}
gpio_clear(&gpio_vaa_disable);
}
void disable_rf_power(void) {
gpio_set(&gpio_vaa_disable);
}
#endif
#ifdef RAD1O
void enable_rf_power(void) {
gpio_set(&gpio_vaa_enable);
}
void disable_rf_power(void) {
gpio_clear(&gpio_vaa_enable);
}
#endif
void led_on(const led_t led) {
gpio_set(&gpio_led[led]);
}
void led_off(const led_t led) {
gpio_clear(&gpio_led[led]);
}
void led_toggle(const led_t led) {
gpio_toggle(&gpio_led[led]);
}
void hw_sync_enable(const hw_sync_mode_t hw_sync_mode){
gpio_write(&gpio_hw_sync_enable, hw_sync_mode==1);
}
void halt_and_flash(const uint32_t duration) {
/* blink LED1, LED2, and LED3 */
while (1)
{
led_on(LED1);
led_on(LED2);
led_on(LED3);
delay(duration);
led_off(LED1);
led_off(LED2);
led_off(LED3);
delay(duration);
}
}

View File

@ -0,0 +1,330 @@
/*
* Copyright 2012 Michael Ossmann <mike@ossmann.com>
* Copyright 2012 Benjamin Vernoux <titanmkd@gmail.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.
*/
#ifndef __HACKRF_CORE_H
#define __HACKRF_CORE_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#include <stdbool.h>
#include "si5351c.h"
#include "spi_ssp.h"
#include "max2837.h"
#include "max5864.h"
#include "mixer.h"
#include "w25q80bv.h"
#include "sgpio.h"
#include "rf_path.h"
#include "cpld_jtag.h"
/* hardware identification number */
#define BOARD_ID_JAWBREAKER 1
#define BOARD_ID_HACKRF_ONE 2
#define BOARD_ID_RAD1O 3
#ifdef JAWBREAKER
#define BOARD_ID BOARD_ID_JAWBREAKER
#endif
#ifdef HACKRF_ONE
#define BOARD_ID BOARD_ID_HACKRF_ONE
#endif
#ifdef RAD1O
#define BOARD_ID BOARD_ID_RAD1O
#endif
/*
* SCU PinMux
*/
/* GPIO Output PinMux */
#define SCU_PINMUX_LED1 (P4_1) /* GPIO2[1] on P4_1 */
#define SCU_PINMUX_LED2 (P4_2) /* GPIO2[2] on P4_2 */
#define SCU_PINMUX_LED3 (P6_12) /* GPIO2[8] on P6_12 */
#ifdef RAD1O
#define SCU_PINMUX_LED4 (PB_6) /* GPIO5[26] on PB_6 */
#endif
#define SCU_PINMUX_EN1V8 (P6_10) /* GPIO3[6] on P6_10 */
/* GPIO Input PinMux */
#define SCU_PINMUX_BOOT0 (P1_1) /* GPIO0[8] on P1_1 */
#define SCU_PINMUX_BOOT1 (P1_2) /* GPIO0[9] on P1_2 */
#ifndef HACKRF_ONE
#define SCU_PINMUX_BOOT2 (P2_8) /* GPIO5[7] on P2_8 */
#define SCU_PINMUX_BOOT3 (P2_9) /* GPIO1[10] on P2_9 */
#endif
#define SCU_PINMUX_PP_LCD_TE (P2_3) /* GPIO5[3] on P2_3 */
#define SCU_PINMUX_PP_LCD_RDX (P2_4) /* GPIO5[4] on P2_4 */
#define SCU_PINMUX_PP_UNUSED (P2_8) /* GPIO5[7] on P2_8 */
#define SCU_PINMUX_PP_LCD_WRX (P2_9) /* GPIO1[10] on P2_9 */
#define SCU_PINMUX_PP_DIR (P2_13) /* GPIO1[13] on P2_13 */
/* USB peripheral */
#ifdef JAWBREAKER
#define SCU_PINMUX_USB_LED0 (P6_8)
#define SCU_PINMUX_USB_LED1 (P6_7)
#endif
/* SSP1 Peripheral PinMux */
#define SCU_SSP1_CIPO (P1_3) /* P1_3 */
#define SCU_SSP1_COPI (P1_4) /* P1_4 */
#define SCU_SSP1_SCK (P1_19) /* P1_19 */
#define SCU_SSP1_CS (P1_20) /* P1_20 */
/* CPLD JTAG interface */
#define SCU_PINMUX_CPLD_TDO (P9_5) /* GPIO5[18] */
#define SCU_PINMUX_CPLD_TCK (P6_1) /* GPIO3[ 0] */
#if (defined HACKRF_ONE || defined RAD1O)
#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)
#define SCU_PINMUX_SGPIO1 (P0_1)
#define SCU_PINMUX_SGPIO2 (P1_15)
#define SCU_PINMUX_SGPIO3 (P1_16)
#define SCU_PINMUX_SGPIO4 (P6_3)
#define SCU_PINMUX_SGPIO5 (P6_6)
#define SCU_PINMUX_SGPIO6 (P2_2)
#define SCU_PINMUX_SGPIO7 (P1_0)
#if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O)
#define SCU_PINMUX_SGPIO8 (P9_6)
#endif
#define SCU_PINMUX_SGPIO9 (P4_3)
#define SCU_PINMUX_SGPIO10 (P1_14)
#define SCU_PINMUX_SGPIO11 (P1_17)
#define SCU_PINMUX_SGPIO12 (P1_18)
#define SCU_PINMUX_SGPIO13 (P4_8)
#define SCU_PINMUX_SGPIO14 (P4_9)
#define SCU_PINMUX_SGPIO15 (P4_10)
/* MAX2837 GPIO (XCVR_CTL) PinMux */
#ifdef RAD1O
#define SCU_XCVR_RXHP (P8_1) /* GPIO[] on P8_1 */
#define SCU_XCVR_B6 (P8_2) /* GPIO[] on P8_2 */
#define SCU_XCVR_B7 (P9_3) /* GPIO[] on P8_3 */
#endif
#define SCU_XCVR_ENABLE (P4_6) /* GPIO2[6] on P4_6 */
#define SCU_XCVR_RXENABLE (P4_5) /* GPIO2[5] on P4_5 */
#define SCU_XCVR_TXENABLE (P4_4) /* GPIO2[4] on P4_4 */
#define SCU_XCVR_CS (P1_20) /* GPIO0[15] on P1_20 */
/* MAX5864 SPI chip select (AD_CS) GPIO PinMux */
#define SCU_AD_CS (P5_7) /* GPIO2[7] on P5_7 */
/* RFFC5071 GPIO serial interface PinMux */
#if (defined JAWBREAKER || defined HACKRF_ONE)
#define SCU_MIXER_ENX (P5_4) /* GPIO2[13] on P5_4 */
#define SCU_MIXER_SCLK (P2_6) /* GPIO5[6] on P2_6 */
#define SCU_MIXER_SDATA (P6_4) /* GPIO3[3] on P6_4 */
#define SCU_MIXER_RESETX (P5_5) /* GPIO2[14] on P5_5 */
#endif
#ifdef RAD1O
#define SCU_VCO_CE (P5_4) /* GPIO2[13] on P5_4 */
#define SCU_VCO_SCLK (P2_6) /* GPIO5[6] on P2_6 */
#define SCU_VCO_SDATA (P6_4) /* GPIO3[3] on P6_4 */
#define SCU_VCO_LE (P5_5) /* GPIO2[14] on P5_5 */
#define SCU_VCO_MUX (PB_5) /* GPIO5[25] on PB_5 */
#define SCU_MIXER_EN (P6_8) /* GPIO5[16] on P6_8 */
#define SCU_SYNT_RFOUT_EN (P6_9) /* GPIO3[5] on P6_9 */
#endif
/* RF LDO control */
#ifdef JAWBREAKER
#define SCU_RF_LDO_ENABLE (P5_0) /* GPIO2[9] on P5_0 */
#endif
/* RF supply (VAA) control */
#ifdef HACKRF_ONE
#define SCU_NO_VAA_ENABLE (P5_0) /* GPIO2[9] on P5_0 */
#endif
#ifdef RAD1O
#define SCU_VAA_ENABLE (P5_0) /* GPIO2[9] on P5_0 */
#endif
/* SPI flash */
#define SCU_SSP0_CIPO (P3_6)
#define SCU_SSP0_COPI (P3_7)
#define SCU_SSP0_SCK (P3_3)
#define SCU_SSP0_CS (P3_8) /* GPIO5[11] on P3_8 */
#define SCU_FLASH_HOLD (P3_4) /* GPIO1[14] on P3_4 */
#define SCU_FLASH_WP (P3_5) /* GPIO1[15] on P3_5 */
/* RF switch control */
#ifdef HACKRF_ONE
#define SCU_HP (P4_0) /* GPIO2[0] on P4_0 */
#define SCU_LP (P5_1) /* GPIO2[10] on P5_1 */
#define SCU_TX_MIX_BP (P5_2) /* GPIO2[11] on P5_2 */
#define SCU_NO_MIX_BYPASS (P1_7) /* GPIO1[0] on P1_7 */
#define SCU_RX_MIX_BP (P5_3) /* GPIO2[12] on P5_3 */
#define SCU_TX_AMP (P5_6) /* GPIO2[15] on P5_6 */
#define SCU_TX (P6_7) /* GPIO5[15] on P6_7 */
#define SCU_MIX_BYPASS (P6_8) /* GPIO5[16] on P6_8 */
#define SCU_RX (P2_5) /* GPIO5[5] on P2_5 */
#define SCU_NO_TX_AMP_PWR (P6_9) /* GPIO3[5] on P6_9 */
#define SCU_AMP_BYPASS (P2_10) /* GPIO0[14] on P2_10 */
#define SCU_RX_AMP (P2_11) /* GPIO1[11] on P2_11 */
#define SCU_NO_RX_AMP_PWR (P2_12) /* GPIO1[12] on P2_12 */
#endif
#ifdef RAD1O
#define SCU_BY_AMP (P1_7) /* GPIO1[0] on P1_7 */
#define SCU_BY_AMP_N (P2_5) /* GPIO5[5] on P2_5 */
#define SCU_TX_RX (P2_10) /* GPIO0[14] on P2_10 */
#define SCU_TX_RX_N (P2_11) /* GPIO1[11] on P2_11 */
#define SCU_BY_MIX (P2_12) /* GPIO1[12] on P2_12 */
#define SCU_BY_MIX_N (P5_1) /* GPIO2[10] on P5_1 */
#define SCU_LOW_HIGH_FILT (P5_2) /* GPIO2[11] on P5_2 */
#define SCU_LOW_HIGH_FILT_N (P5_3) /* GPIO2[12] on P5_3 */
#define SCU_TX_AMP (P5_6) /* GPIO2[15] on P5_6 */
#define SCU_RX_LNA (P6_7) /* GPIO5[15] on P6_7 */
#endif
#define SCU_PINMUX_PP_D0 (P7_0) /* GPIO3[8] */
#define SCU_PINMUX_PP_D1 (P7_1) /* GPIO3[9] */
#define SCU_PINMUX_PP_D2 (P7_2) /* GPIO3[10] */
#define SCU_PINMUX_PP_D3 (P7_3) /* GPIO3[11] */
#define SCU_PINMUX_PP_D4 (P7_4) /* GPIO3[12] */
#define SCU_PINMUX_PP_D5 (P7_5) /* GPIO3[13] */
#define SCU_PINMUX_PP_D6 (P7_6) /* GPIO3[14] */
#define SCU_PINMUX_PP_D7 (P7_7) /* GPIO3[15] */
/* 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_PP_TDO (P1_5) /* GPIO1[8] */
#define SCU_PINMUX_SD_POW (P1_5) /* GPIO1[8] */
#define SCU_PINMUX_SD_CMD (P1_6) /* GPIO1[9] */
#define SCU_PINMUX_PP_TMS (P1_8) /* GPIO1[1] */
#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_PP_IO_STBX (P2_0) /* GPIO5[0] */
#define SCU_PINMUX_PP_ADDR (P2_1) /* GPIO5[1] */
#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)
typedef enum {
TRANSCEIVER_MODE_OFF = 0,
TRANSCEIVER_MODE_RX = 1,
TRANSCEIVER_MODE_TX = 2,
TRANSCEIVER_MODE_SS = 3,
TRANSCEIVER_MODE_CPLD_UPDATE = 4,
TRANSCEIVER_MODE_RX_SWEEP = 5,
} transceiver_mode_t;
typedef enum {
HW_SYNC_MODE_OFF = 0,
HW_SYNC_MODE_ON = 1,
} hw_sync_mode_t;
typedef enum {
CLOCK_SOURCE_HACKRF = 0,
CLOCK_SOURCE_EXTERNAL = 1,
CLOCK_SOURCE_PORTAPACK = 2,
} clock_source_t;
void delay(uint32_t duration);
/* TODO: Hide these configurations */
extern si5351c_driver_t clock_gen;
extern const ssp_config_t ssp_config_w25q80bv;
extern const ssp_config_t ssp_config_max2837;
extern const ssp_config_t ssp_config_max5864;
extern max2837_driver_t max2837;
extern max5864_driver_t max5864;
extern mixer_driver_t mixer;
extern w25q80bv_driver_t spi_flash;
extern sgpio_config_t sgpio_config;
extern rf_path_t rf_path;
extern jtag_t jtag_cpld;
extern i2c_bus_t i2c0;
void cpu_clock_init(void);
void ssp1_set_mode_max2837(void);
void ssp1_set_mode_max5864(void);
void pin_setup(void);
void enable_1v8_power(void);
void disable_1v8_power(void);
bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom);
bool sample_rate_set(const uint32_t sampling_rate_hz);
bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz);
clock_source_t activate_best_clock_source(void);
#if (defined HACKRF_ONE || defined RAD1O)
void enable_rf_power(void);
void disable_rf_power(void);
#endif
typedef enum {
LED1 = 0,
LED2 = 1,
LED3 = 2,
LED4 = 3,
} led_t;
void led_on(const led_t led);
void led_off(const led_t led);
void led_toggle(const led_t led);
void hw_sync_enable(const hw_sync_mode_t hw_sync_mode);
void halt_and_flash(const uint32_t duration);
#ifdef __cplusplus
}
#endif
#endif /* __HACKRF_CORE_H */

View File

@ -0,0 +1,104 @@
/*
* Copyright (C) 2019 Jared Boone, ShareBrained Technology, Inc.
*
* 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 "hackrf_ui.h"
#include "ui_portapack.h"
#include "ui_rad1o.h"
#include <stddef.h>
#define UNUSED(x) (void)(x)
/* Stub functions for null UI function table */
void hackrf_ui_init_null(void) { }
void hackrf_ui_deinit_null(void) { }
void hackrf_ui_set_frequency_null(uint64_t frequency) { UNUSED(frequency); }
void hackrf_ui_set_sample_rate_null(uint32_t sample_rate) { UNUSED(sample_rate); }
void hackrf_ui_set_direction_null(const rf_path_direction_t direction) { UNUSED(direction); }
void hackrf_ui_set_filter_bw_null(uint32_t bandwidth) { UNUSED(bandwidth); }
void hackrf_ui_set_lna_power_null(bool lna_on) { UNUSED(lna_on); }
void hackrf_ui_set_bb_lna_gain_null(const uint32_t gain_db) { UNUSED(gain_db); }
void hackrf_ui_set_bb_vga_gain_null(const uint32_t gain_db) { UNUSED(gain_db); }
void hackrf_ui_set_bb_tx_vga_gain_null(const uint32_t gain_db) { UNUSED(gain_db); }
void hackrf_ui_set_first_if_frequency_null(const uint64_t frequency) { UNUSED(frequency); }
void hackrf_ui_set_filter_null(const rf_path_filter_t filter) { UNUSED(filter); }
void hackrf_ui_set_antenna_bias_null(bool antenna_bias) { UNUSED(antenna_bias); }
void hackrf_ui_set_clock_source_null(clock_source_t source) { UNUSED(source); }
void hackrf_ui_set_transceiver_mode_null(transceiver_mode_t mode) { UNUSED(mode); }
bool hackrf_ui_operacake_gpio_compatible_null(void) { return true; }
/* Null UI function table, used if there's no hardware UI detected. Eliminates the
* need to check for null UI before calling a function in the table.
*/
static const hackrf_ui_t hackrf_ui_null = {
&hackrf_ui_init_null,
&hackrf_ui_deinit_null,
&hackrf_ui_set_frequency_null,
&hackrf_ui_set_sample_rate_null,
&hackrf_ui_set_direction_null,
&hackrf_ui_set_filter_bw_null,
&hackrf_ui_set_lna_power_null,
&hackrf_ui_set_bb_lna_gain_null,
&hackrf_ui_set_bb_vga_gain_null,
&hackrf_ui_set_bb_tx_vga_gain_null,
&hackrf_ui_set_first_if_frequency_null,
&hackrf_ui_set_filter_null,
&hackrf_ui_set_antenna_bias_null,
&hackrf_ui_set_clock_source_null,
&hackrf_ui_set_transceiver_mode_null,
&hackrf_ui_operacake_gpio_compatible_null
};
static const hackrf_ui_t* ui = NULL;
static bool ui_enabled = true;
const hackrf_ui_t* hackrf_ui(void) {
/* Detect on first use. If no UI hardware is detected, use a stub function table. */
if( ui == NULL && ui_enabled ) {
#ifdef HACKRF_ONE
if( portapack_hackrf_ui_init ) {
ui = portapack_hackrf_ui_init();
}
#endif
#ifdef RAD1O
if( rad1o_ui_setup ) {
ui = rad1o_ui_setup();
}
#endif
}
if( ui == NULL ) {
ui = &hackrf_ui_null;
}
return ui;
}
void hackrf_ui_set_enable(bool enabled) {
if (ui_enabled != enabled) {
ui_enabled = enabled;
hackrf_ui()->deinit();
ui = NULL;
if (enabled) {
hackrf_ui()->init();
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2018 Jared Boone, ShareBrained Technology, Inc.
*
* 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 HACKRF_UI_H
#define HACKRF_UI_H
#include <hackrf_core.h>
#include <stdint.h>
typedef void (*hackrf_ui_init_fn)(void);
typedef void (*hackrf_ui_deinit_fn)(void);
typedef void (*hackrf_ui_set_frequency_fn)(uint64_t frequency);
typedef void (*hackrf_ui_set_sample_rate_fn)(uint32_t sample_rate);
typedef void (*hackrf_ui_set_direction_fn)(const rf_path_direction_t direction);
typedef void (*hackrf_ui_set_filter_bw_fn)(uint32_t bandwidth);
typedef void (*hackrf_ui_set_lna_power_fn)(bool lna_on);
typedef void (*hackrf_ui_set_bb_lna_gain_fn)(const uint32_t gain_db);
typedef void (*hackrf_ui_set_bb_vga_gain_fn)(const uint32_t gain_db);
typedef void (*hackrf_ui_set_bb_tx_vga_gain_fn)(const uint32_t gain_db);
typedef void (*hackrf_ui_set_first_if_frequency_fn)(const uint64_t frequency);
typedef void (*hackrf_ui_set_filter_fn)(const rf_path_filter_t filter);
typedef void (*hackrf_ui_set_antenna_bias_fn)(bool antenna_bias);
typedef void (*hackrf_ui_set_clock_source_fn)(clock_source_t source);
typedef void (*hackrf_ui_set_transceiver_mode_fn)(transceiver_mode_t mode);
typedef bool (*hackrf_ui_operacake_gpio_compatible_fn)(void);
typedef struct {
hackrf_ui_init_fn init;
hackrf_ui_deinit_fn deinit;
hackrf_ui_set_frequency_fn set_frequency;
hackrf_ui_set_sample_rate_fn set_sample_rate;
hackrf_ui_set_direction_fn set_direction;
hackrf_ui_set_filter_bw_fn set_filter_bw;
hackrf_ui_set_lna_power_fn set_lna_power;
hackrf_ui_set_bb_lna_gain_fn set_bb_lna_gain;
hackrf_ui_set_bb_vga_gain_fn set_bb_vga_gain;
hackrf_ui_set_bb_tx_vga_gain_fn set_bb_tx_vga_gain;
hackrf_ui_set_first_if_frequency_fn set_first_if_frequency;
hackrf_ui_set_filter_fn set_filter;
hackrf_ui_set_antenna_bias_fn set_antenna_bias;
hackrf_ui_set_clock_source_fn set_clock_source;
hackrf_ui_set_transceiver_mode_fn set_transceiver_mode;
hackrf_ui_operacake_gpio_compatible_fn operacake_gpio_compatible;
} hackrf_ui_t;
/* TODO: Lame hack to know that PortaPack was detected.
* In the future, whatever UI was detected will be returned here,
* or NULL if no UI was detected.
*/
const hackrf_ui_t* hackrf_ui(void);
void hackrf_ui_set_enable(bool);
#endif

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 "i2c_bus.h"
void i2c_bus_start(i2c_bus_t* const bus, const void* const config) {
bus->start(bus, config);
}
void i2c_bus_stop(i2c_bus_t* const bus) {
bus->stop(bus);
}
void i2c_bus_transfer(
i2c_bus_t* const bus,
const uint_fast8_t peripheral_address,
const uint8_t* const tx, const size_t tx_count,
uint8_t* const rx, const size_t rx_count
) {
bus->transfer(bus, peripheral_address, tx, tx_count, rx, rx_count);
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 __I2C_BUS_H__
#define __I2C_BUS_H__
#include <stdint.h>
#include <stddef.h>
struct i2c_bus_t;
typedef struct i2c_bus_t i2c_bus_t;
struct i2c_bus_t {
void* const obj;
void (*start)(i2c_bus_t* const bus, const void* const config);
void (*stop)(i2c_bus_t* const bus);
void (*transfer)(
i2c_bus_t* const bus,
const uint_fast8_t peripheral_address,
const uint8_t* const tx, const size_t tx_count,
uint8_t* const rx, const size_t rx_count
);
};
void i2c_bus_start(i2c_bus_t* const bus, const void* const config);
void i2c_bus_stop(i2c_bus_t* const bus);
void i2c_bus_transfer(
i2c_bus_t* const bus,
const uint_fast8_t peripheral_address,
const uint8_t* const tx, const size_t tx_count,
uint8_t* const rx, const size_t rx_count
);
#endif/*__I2C_BUS_H__*/

View File

@ -0,0 +1,79 @@
/*
* 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.
*/
#include "i2c_lpc.h"
#include <libopencm3/lpc43xx/i2c.h>
/* FIXME return i2c0 status from each function */
void i2c_lpc_start(i2c_bus_t* const bus, const void* const _config) {
const i2c_lpc_config_t* const config = _config;
const uint32_t port = (uint32_t)bus->obj;
i2c_init(port, config->duty_cycle_count);
}
void i2c_lpc_stop(i2c_bus_t* const bus) {
const uint32_t port = (uint32_t)bus->obj;
i2c_disable(port);
}
void i2c_lpc_transfer(i2c_bus_t* const bus,
const uint_fast8_t peripheral_address,
const uint8_t* const data_tx, const size_t count_tx,
uint8_t* const data_rx, const size_t count_rx
) {
const uint32_t port = (uint32_t)bus->obj;
size_t i;
bool ack = false;
if (data_tx && (count_tx > 0)) {
i2c_tx_start(port);
i2c_tx_byte(port, (peripheral_address << 1) | I2C_WRITE);
for(i=0; i<count_tx; i++) {
i2c_tx_byte(port, data_tx[i]);
}
}
if (data_rx && (count_rx > 0)) {
i2c_tx_start(port);
i2c_tx_byte(port, (peripheral_address << 1) | I2C_READ);
for(i=0; i<count_rx; i++) {
/* ACK each byte except the last */
ack = (i!=count_rx-1);
data_rx[i] = i2c_rx_byte(port, ack);
}
}
i2c_stop(port);
}
bool i2c_probe(i2c_bus_t* const bus, const uint_fast8_t device_address) {
const uint32_t port = (uint32_t)bus->obj;
i2c_tx_start(port);
i2c_tx_byte(port, (device_address << 1) | I2C_WRITE);
const bool detected = (I2C_STAT(port) == 0x18);
i2c_stop(port);
return detected;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 __I2C_LPC_H__
#define __I2C_LPC_H__
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "i2c_bus.h"
typedef struct i2c_lpc_config_t {
const uint16_t duty_cycle_count;
} i2c_lpc_config_t;
void i2c_lpc_start(i2c_bus_t* const bus, const void* const config);
void i2c_lpc_stop(i2c_bus_t* const bus);
void i2c_lpc_transfer(i2c_bus_t* const bus,
const uint_fast8_t peripheral_address,
const uint8_t* const data_tx, const size_t count_tx,
uint8_t* const data_rx, const size_t count_rx
);
bool i2c_probe(i2c_bus_t* const bus, const uint_fast8_t device_address);
#endif/*__I2C_LPC_H__*/

View File

@ -0,0 +1,23 @@
# 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.
.data
.section .m0_bin, "ax"
.incbin "${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

@ -0,0 +1,349 @@
/*
* Copyright 2012 Will Code? (TODO: Proper attribution)
* Copyright 2014 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.
*/
/*
* 'gcc -DTEST -DDEBUG -O2 -o test max2837.c' prints out what test
* program would do if it had a real spi library
*
* 'gcc -DTEST -DBUS_PIRATE -O2 -o test max2837.c' prints out bus
* pirate commands to do the same thing.
*/
#include <stdint.h>
#include <string.h>
#include "max2837.h"
#include "max2837_regs.def" // private register def macros
/* Default register values. */
static const uint16_t max2837_regs_default[MAX2837_NUM_REGS] = {
0x150, /* 0 */
0x002, /* 1 */
0x1f4, /* 2 */
0x1b9, /* 3 */
0x00a, /* 4 */
0x080, /* 5 */
0x006, /* 6 */
0x000, /* 7 */
0x080, /* 8 */
0x018, /* 9 */
0x058, /* 10 */
0x016, /* 11 */
0x24f, /* 12 */
0x150, /* 13 */
0x1c5, /* 14 */
0x081, /* 15 */
0x01c, /* 16 */
0x155, /* 17 */
0x155, /* 18 */
0x153, /* 19 */
0x241, /* 20 */
/*
* Charge Pump Common Mode Enable bit (0) of register 21 must be set or TX
* does not work. Page 1 of the SPI doc says not to set it (0x02c), but
* page 21 says it should be set by default (0x02d).
*/
0x02d, /* 21 */
0x1a9, /* 22 */
0x24f, /* 23 */
0x180, /* 24 */
0x100, /* 25 */
0x3ca, /* 26 */
0x3e3, /* 27 */
0x0c0, /* 28 */
0x3f0, /* 29 */
0x080, /* 30 */
0x000 }; /* 31 */
/* Set up all registers according to defaults specified in docs. */
static void max2837_init(max2837_driver_t* const drv)
{
drv->target_init(drv);
max2837_set_mode(drv, MAX2837_MODE_SHUTDOWN);
memcpy(drv->regs, max2837_regs_default, sizeof(drv->regs));
drv->regs_dirty = 0xffffffff;
/* Write default register values to chip. */
max2837_regs_commit(drv);
}
/*
* Set up pins for GPIO and SPI control, configure SSP peripheral for SPI, and
* set our own default register configuration.
*/
void max2837_setup(max2837_driver_t* const drv)
{
max2837_init(drv);
/* Use SPI control instead of B1-B7 pins for gain settings. */
set_MAX2837_TXVGA_GAIN_SPI_EN(drv, 1);
set_MAX2837_TXVGA_GAIN_MSB_SPI_EN(drv, 1);
//set_MAX2837_TXVGA_GAIN(0x3f); /* maximum attenuation */
set_MAX2837_TXVGA_GAIN(drv, 0x00); /* minimum attenuation */
set_MAX2837_VGAMUX_enable(drv, 1);
set_MAX2837_VGA_EN(drv, 1);
set_MAX2837_HPC_RXGAIN_EN(drv, 0);
set_MAX2837_HPC_STOP(drv, MAX2837_STOP_1K);
set_MAX2837_LNAgain_SPI_EN(drv, 1);
set_MAX2837_LNAgain(drv, MAX2837_LNAgain_MAX); /* maximum gain */
set_MAX2837_VGAgain_SPI_EN(drv, 1);
set_MAX2837_VGA(drv, 0x18); /* reasonable gain for noisy 2.4GHz environment */
/* maximum rx output common-mode voltage */
set_MAX2837_BUFF_VCM(drv, MAX2837_BUFF_VCM_1_25);
/* configure baseband filter for 8 MHz TX */
set_MAX2837_LPF_EN(drv, 1);
set_MAX2837_ModeCtrl(drv, MAX2837_ModeCtrl_RxLPF);
set_MAX2837_FT(drv, MAX2837_FT_5M);
max2837_regs_commit(drv);
}
static uint16_t max2837_read(max2837_driver_t* const drv, uint8_t r) {
uint16_t value = (1 << 15) | (r << 10);
spi_bus_transfer(drv->bus, &value, 1);
return value & 0x3ff;
}
static void max2837_write(max2837_driver_t* const drv, uint8_t r, uint16_t v) {
uint16_t value = (r << 10) | (v & 0x3ff);
spi_bus_transfer(drv->bus, &value, 1);
}
uint16_t max2837_reg_read(max2837_driver_t* const drv, uint8_t r)
{
if ((drv->regs_dirty >> r) & 0x1) {
drv->regs[r] = max2837_read(drv, r);
};
return drv->regs[r];
}
void max2837_reg_write(max2837_driver_t* const drv, uint8_t r, uint16_t v)
{
drv->regs[r] = v;
max2837_write(drv, r, v);
MAX2837_REG_SET_CLEAN(drv, r);
}
static inline void max2837_reg_commit(max2837_driver_t* const drv, uint8_t r)
{
max2837_reg_write(drv, r, drv->regs[r]);
}
void max2837_regs_commit(max2837_driver_t* const drv)
{
int r;
for(r = 0; r < MAX2837_NUM_REGS; r++) {
if ((drv->regs_dirty >> r) & 0x1) {
max2837_reg_commit(drv, r);
}
}
}
void max2837_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode) {
drv->set_mode(drv, new_mode);
}
max2837_mode_t max2837_mode(max2837_driver_t* const drv) {
return drv->mode;
}
void max2837_start(max2837_driver_t* const drv)
{
set_MAX2837_EN_SPI(drv, 1);
max2837_regs_commit(drv);
max2837_set_mode(drv, MAX2837_MODE_STANDBY);
}
void max2837_tx(max2837_driver_t* const drv)
{
set_MAX2837_ModeCtrl(drv, MAX2837_ModeCtrl_TxLPF);
max2837_regs_commit(drv);
max2837_set_mode(drv, MAX2837_MODE_TX);
}
void max2837_rx(max2837_driver_t* const drv)
{
set_MAX2837_ModeCtrl(drv, MAX2837_ModeCtrl_RxLPF);
max2837_regs_commit(drv);
max2837_set_mode(drv, MAX2837_MODE_RX);
}
void max2837_stop(max2837_driver_t* const drv)
{
set_MAX2837_EN_SPI(drv, 0);
max2837_regs_commit(drv);
max2837_set_mode(drv, MAX2837_MODE_SHUTDOWN);
}
void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq)
{
uint8_t band;
uint8_t lna_band;
uint32_t div_frac;
uint32_t div_int;
uint32_t div_rem;
uint32_t div_cmp;
int i;
/* Select band. Allow tuning outside specified bands. */
if (freq < 2400000000U) {
band = MAX2837_LOGEN_BSW_2_3;
lna_band = MAX2837_LNAband_2_4;
}
else if (freq < 2500000000U) {
band = MAX2837_LOGEN_BSW_2_4;
lna_band = MAX2837_LNAband_2_4;
}
else if (freq < 2600000000U) {
band = MAX2837_LOGEN_BSW_2_5;
lna_band = MAX2837_LNAband_2_6;
}
else {
band = MAX2837_LOGEN_BSW_2_6;
lna_band = MAX2837_LNAband_2_6;
}
/* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */
div_int = freq / 30000000;
div_rem = freq % 30000000;
div_frac = 0;
div_cmp = 30000000;
for( i = 0; i < 20; i++) {
div_frac <<= 1;
div_cmp >>= 1;
if (div_rem > div_cmp) {
div_frac |= 0x1;
div_rem -= div_cmp;
}
}
/* Band settings */
set_MAX2837_LOGEN_BSW(drv, band);
set_MAX2837_LNAband(drv, lna_band);
/* Write order matters here, so commit INT and FRAC_HI before
* committing FRAC_LO, which is the trigger for VCO
* auto-select. TODO - it's cleaner this way, but it would be
* faster to explicitly commit the registers explicitly so the
* dirty bits aren't scanned twice. */
set_MAX2837_SYN_INT(drv, div_int);
set_MAX2837_SYN_FRAC_HI(drv, (div_frac >> 10) & 0x3ff);
max2837_regs_commit(drv);
set_MAX2837_SYN_FRAC_LO(drv, div_frac & 0x3ff);
max2837_regs_commit(drv);
}
typedef struct {
uint32_t bandwidth_hz;
uint32_t ft;
} max2837_ft_t;
static const max2837_ft_t max2837_ft[] = {
{ 1750000, MAX2837_FT_1_75M },
{ 2500000, MAX2837_FT_2_5M },
{ 3500000, MAX2837_FT_3_5M },
{ 5000000, MAX2837_FT_5M },
{ 5500000, MAX2837_FT_5_5M },
{ 6000000, MAX2837_FT_6M },
{ 7000000, MAX2837_FT_7M },
{ 8000000, MAX2837_FT_8M },
{ 9000000, MAX2837_FT_9M },
{ 10000000, MAX2837_FT_10M },
{ 12000000, MAX2837_FT_12M },
{ 14000000, MAX2837_FT_14M },
{ 15000000, MAX2837_FT_15M },
{ 20000000, MAX2837_FT_20M },
{ 24000000, MAX2837_FT_24M },
{ 28000000, MAX2837_FT_28M },
{ 0, 0 },
};
uint32_t max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandwidth_hz) {
const max2837_ft_t* p = max2837_ft;
while( p->bandwidth_hz != 0 ) {
if( p->bandwidth_hz >= bandwidth_hz ) {
break;
}
p++;
}
if( p->bandwidth_hz != 0 ) {
set_MAX2837_FT(drv, p->ft);
max2837_regs_commit(drv);
}
return p->bandwidth_hz;
}
bool max2837_set_lna_gain(max2837_driver_t* const drv, const uint32_t gain_db) {
uint16_t val;
switch(gain_db){
case 40:
val = MAX2837_LNAgain_MAX;
break;
case 32:
val = MAX2837_LNAgain_M8;
break;
case 24:
val = MAX2837_LNAgain_M16;
break;
case 16:
val = MAX2837_LNAgain_M24;
break;
case 8:
val = MAX2837_LNAgain_M32;
break;
case 0:
val = MAX2837_LNAgain_M40;
break;
default:
return false;
}
set_MAX2837_LNAgain(drv, val);
max2837_reg_commit(drv, 1);
return true;
}
bool max2837_set_vga_gain(max2837_driver_t* const drv, const uint32_t gain_db) {
if( (gain_db & 0x1) || gain_db > 62)/* 0b11111*2 */
return false;
set_MAX2837_VGA(drv, 31-(gain_db >> 1) );
max2837_reg_commit(drv, 5);
return true;
}
bool max2837_set_txvga_gain(max2837_driver_t* const drv, const uint32_t gain_db) {
uint16_t val=0;
if(gain_db <16){
val = 31-gain_db;
val |= (1 << 5); // bit6: 16db
} else{
val = 31-(gain_db-16);
}
set_MAX2837_TXVGA_GAIN(drv, val);
max2837_reg_commit(drv, 29);
return true;
}

View File

@ -0,0 +1,92 @@
/*
* Copyright 2012 Will Code? (TODO: Proper attribution)
* Copyright 2014 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 __MAX2837_H
#define __MAX2837_H
#include <stdint.h>
#include <stdbool.h>
#include "gpio.h"
#include "spi_bus.h"
/* 32 registers, each containing 10 bits of data. */
#define MAX2837_NUM_REGS 32
#define MAX2837_DATA_REGS_MAX_VALUE 1024
typedef enum {
MAX2837_MODE_SHUTDOWN,
MAX2837_MODE_STANDBY,
MAX2837_MODE_TX,
MAX2837_MODE_RX
} max2837_mode_t;
struct max2837_driver_t;
typedef struct max2837_driver_t max2837_driver_t;
struct max2837_driver_t {
spi_bus_t* const bus;
gpio_t gpio_enable;
gpio_t gpio_rx_enable;
gpio_t gpio_tx_enable;
void (*target_init)(max2837_driver_t* const drv);
void (*set_mode)(max2837_driver_t* const drv, const max2837_mode_t new_mode);
max2837_mode_t mode;
uint16_t regs[MAX2837_NUM_REGS];
uint32_t regs_dirty;
};
/* Initialize chip. */
extern void max2837_setup(max2837_driver_t* const drv);
/* Read a register via SPI. Save a copy to memory and return
* value. Mark clean. */
extern uint16_t max2837_reg_read(max2837_driver_t* const drv, uint8_t r);
/* Write value to register via SPI and save a copy to memory. Mark
* clean. */
extern void max2837_reg_write(max2837_driver_t* const drv, uint8_t r, uint16_t v);
/* Write all dirty registers via SPI from memory. Mark all clean. Some
* operations require registers to be written in a certain order. Use
* provided routines for those operations. */
extern void max2837_regs_commit(max2837_driver_t* const drv);
max2837_mode_t max2837_mode(max2837_driver_t* const drv);
void max2837_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode);
/* Turn on/off all chip functions. Does not control oscillator and CLKOUT */
extern void max2837_start(max2837_driver_t* const drv);
extern void max2837_stop(max2837_driver_t* const drv);
/* Set frequency in Hz. Frequency setting is a multi-step function
* where order of register writes matters. */
extern void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq);
uint32_t max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandwidth_hz);
bool max2837_set_lna_gain(max2837_driver_t* const drv, const uint32_t gain_db);
bool max2837_set_vga_gain(max2837_driver_t* const drv, const uint32_t gain_db);
bool max2837_set_txvga_gain(max2837_driver_t* const drv, const uint32_t gain_db);
extern void max2837_tx(max2837_driver_t* const drv);
extern void max2837_rx(max2837_driver_t* const drv);
#endif // __MAX2837_H

View File

@ -0,0 +1,408 @@
/* -*- mode: c -*- */
#ifndef __MAX2837_REGS_DEF
#define __MAX2837_REGS_DEF
/* Generate static inline accessors that operate on the global
* regs. Done this way to (1) allow defs to be scraped out and used
* elsewhere, e.g. in scripts, (2) to avoid dealing with endian
* (structs). This may be used in firmware, or on host predefined
* register loads. */
#define MAX2837_REG_SET_CLEAN(_d, _r) (_d->regs_dirty &= ~(1UL<<_r))
#define MAX2837_REG_SET_DIRTY(_d, _r) (_d->regs_dirty |= (1UL<<_r))
/* On set_, register is always set dirty, even if nothing
* changed. This makes sure that write that have side effects,
* e.g. frequency setting, are not skipped. */
/* n=name, r=regnum, o=offset (bits from LSB), l=length (bits) */
#define __MREG__(n,r,o,l) \
static inline uint16_t get_##n(max2837_driver_t* const _d) { \
return (_d->regs[r] >> (o-l+1)) & ((1<<l)-1); \
} \
static inline void set_##n(max2837_driver_t* const _d, uint16_t v) { \
_d->regs[r] &= ~(((1<<l)-1)<<(o-l+1)); \
_d->regs[r] |= ((v&((1<<l)-1))<<(o-l+1)); \
MAX2837_REG_SET_DIRTY(_d, r); \
}
/* REG 0 */
__MREG__(MAX2837_LNA_EN, 0,0,1)
__MREG__(MAX2837_Mixer_EN, 0,1,1)
__MREG__(MAX2837_RxLO_EN, 0,2,1)
__MREG__(MAX2837_Lbias, 0,4,2)
#define MAX2837_Lbias_LOWEST 0
#define MAX2837_Lbias_NOMINAL 2
#define MAX2837_Lbias_HIGHEST 3
__MREG__(MAX2837_Mbias, 0,6,2)
#define MAX2837_Mbias_LOWEST 0
#define MAX2837_Mbias_NOMINAL 2
#define MAX2837_Mbias_HIGHEST 3
__MREG__(MAX2837_buf, 0,8,2)
#define MAX2837_buf_LOWEST 0
#define MAX2837_buf_NOMINAL 2
#define MAX2837_buf_HIGHEST 3
__MREG__(MAX2837_LNAband, 0,9,1)
#define MAX2837_LNAband_2_4 0 // 2.3-2.5 GHz
#define MAX2837_LNAband_2_6 1 // 2.5-2.7 GHz
/* REG 1 */
__MREG__(MAX2837_LNAtune, 1,0,1)
#define MAX2837_LNAtune_NOMINAL 0
#define MAX2837_LNAtune_DOWN 1
__MREG__(MAX2837_LNAde_Q,1,1,1)
#define MAX2837_LNAde_Q_NOMINAL 0
#define MAX2837_LNAde_Q_2DB 1
__MREG__(MAX2837_LNAgain,1,4,3)
#define MAX2837_LNAgain_MAX 0b000 // Pad in 8dB steps, bits reversed
#define MAX2837_LNAgain_M8 0b100
#define MAX2837_LNAgain_M16 0b010
#define MAX2837_LNAgain_M24 0b110
#define MAX2837_LNAgain_M32 0b011
#define MAX2837_LNAgain_M40 0b111
__MREG__(MAX2837_iqerr_trim,1,9,5)
// 0b00000 = +4.0 degree phase error
// 0b01111 = 0.0
// 0b11111 = -4.0
/* REG 2 */
__MREG__(MAX2837_LPF_EN,2,0,1)
__MREG__(MAX2837_TxBB_EN,2,1,1)
__MREG__(MAX2837_ModeCtrl,2,3,2)
#define MAX2837_ModeCtrl_RxCalibration 0
#define MAX2837_ModeCtrl_RxLPF 1
#define MAX2837_ModeCtrl_TxLPF 2
#define MAX2837_ModeCtrl_LPFTrim 3
__MREG__(MAX2837_FT,2,7,4)
#define MAX2837_FT_1_75M 0
#define MAX2837_FT_2_5M 1
#define MAX2837_FT_3_5M 2
#define MAX2837_FT_5M 3
#define MAX2837_FT_5_5M 4
#define MAX2837_FT_6M 5
#define MAX2837_FT_7M 6
#define MAX2837_FT_8M 7
#define MAX2837_FT_9M 8
#define MAX2837_FT_10M 9
#define MAX2837_FT_12M 10
#define MAX2837_FT_14M 11
#define MAX2837_FT_15M 12
#define MAX2837_FT_20M 13
#define MAX2837_FT_24M 14
#define MAX2837_FT_28M 15
__MREG__(MAX2837_dF,2,9,2)
#define MAX2837_dF_M10 0b00 // -10%
#define MAX2837_dF_NOMINAL 0b01
#define MAX2837_dF_10 0b11 // +10%
/* REG 3 */
__MREG__(MAX2837_PT_SPI,3,3,4) // slowest=1111 fastest=0000 nom=1001
__MREG__(MAX2837_Bqd,3,6,3) // MSB doubles bias current, lower 2 25% each
__MREG__(MAX2837_TxRPCM,3,9,3) // 000=1.00V, 0.05V steps, 111 not allowed
/* REG 4 */
__MREG__(MAX2837_RP,4,1,2) // 20% steps, 00=lowest, 11=highest
__MREG__(MAX2837_TxBuff,4,3,2) // 25% steps, 00=lowest, 11=highest
__MREG__(MAX2837_VGA_EN,4,4,1)
__MREG__(MAX2837_VGAMUX_enable,4,5,1)
__MREG__(MAX2837_BUFF_Curr,4,7,2) // 250uA + 125uA steps
__MREG__(MAX2837_BUFF_VCM,4,9,2) // VGA common mode
#define MAX2837_BUFF_VCM_0_9 0 // 0.9V
#define MAX2837_BUFF_VCM_1_0 1 // 1.0V
#define MAX2837_BUFF_VCM_1_1 2 // 1.1V
#define MAX2837_BUFF_VCM_1_25 3 // 1.25V
/* REG 5 */
__MREG__(MAX2837_VGA,5,4,5) // max=00000, attenuation in 2dB steps
__MREG__(MAX2837_sel_In1_In2,5,5,1)
#define MAX2837_sel_In1_In2_RXVGA 0
#define MAX2837_sel_In1_In2_TXAM 1
__MREG__(MAX2837_turbo15n20,5,6,1)
__MREG__(MAX2837_VGA_Curr,5,8,2) // 01=default, 00=-33%, 10=+33%, 11=+67%
__MREG__(MAX2837_fuse_arm,5,9,1)
/* REG 6 */
__MREG__(MAX2837_RSSI_EN,6,6,1) // enable RSSI
__MREG__(MAX2837_RSSI_MUX,6,7,1)
#define MAX2837_RSSI_MUX_RSSI 0
#define MAX2837_RSSI_MUX_TEMP 1
__MREG__(MAX2837_RSSI_MODE,6,8,1) // set to override RXHP pin
__MREG__(MAX2837_LPF_MODE_SEL,6,9,1) // set to enable mode in reg 2 ModeCtrl
/* REG 7 is R/O */
// D4:0 ts_adc (temp sensor)
// D9:5 zeros or test outputs
/* REG 8 */
__MREG__(MAX2837_LNAgain_SPI_EN,8,0,1) // set to override pin control of LNA
__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,5) // down=00000, up=11111, nom=10000
__MREG__(MAX2837_BIAS_TRIM_CNTRL,8,8,1) // enable BIAS_TRIM_SPI value
__MREG__(MAX2837_RX_IQERR_SPI_EN,8,9,1) // ???
/* REG 9 */
__MREG__(MAX2837_ts_adc_trigger,9,0,1) // temp sensor trigger (one shot)
__MREG__(MAX2837_ts_en,9,1,1) // temp sensor enable (before trigger)
__MREG__(MAX2837_LPFtrim_SPI_EN,9,2,1)
__MREG__(MAX2837_DOUT_DRVH,9,3,1)
#define MAX2837_DOUT_DRVH_1X 0
#define MAX2837_DOUT_DRVH_4X 1
__MREG__(MAX2837_DOUT_PU,9,4,1) // set to enable CMOS PU (default), else OD
__MREG__(MAX2837_DOUT_SEL,9,7,3)
#define MAX2837_DOUT_SEL_SPI 0 // default, SPI comm
#define MAX2837_DOUT_SEL_PLL_LOCK_DETECT 1
#define MAX2837_DOUT_SEL_VAS_TEST_OUT 2
#define MAX2837_DOUT_SEL_HPFSM_TEST_OUT 3
#define MAX2837_DOUT_SEL_LOGEN_TRIM_OUT 4
#define MAX2837_DOUT_SEL_RX_FUSE_GASKET 5
#define MAX2837_DOUT_SEL_TX_FUSE_GASKET 6
#define MAX2837_DOUT_SEL_ZERO 7
__MREG__(MAX2837_fuse_sh,9,8,1) // ???
__MREG__(MAX2837_fuse_burn_gkt,9,9,1) // enable (don't)
/* REG 10 */
__MREG__(MAX2837_TXCAL_GAIN,10,2,2) // 00=default, steps of +10dB
__MREG__(MAX2837_TXCAL_V2I_FILT,10,5,3) // 000=+12%, 111=-16%, 011=default
__MREG__(MAX2837_TX_BIAS_ADJ,10,7,2) // 00=-10%, 01=default, 10=+10%, 11=+20%
/* REG 11 */
__MREG__(MAX2837_AMD_SPI_EN,11,0,1) // enable AM detector
__MREG__(MAX2837_TXMXR_V2I_GAIN,11,4,4) // 0000=max, steps of -0.5dB
/* REG 12 */
__MREG__(MAX2837_HPC_10M,12,1,2) // steps of 0.4uS (0.0-1.2)
__MREG__(MAX2837_HPC_10M_GAIN,12,3,2) // steps of 0.4uS (0.0-1.2)
__MREG__(MAX2837_HPC_600K,12,6,3) // steps of 0.8uS (0.0-4.8), 7=stay 1
__MREG__(MAX2837_HPC_600K_GAIN,12,9,3) // steps of 0.8uS (0.0-4.8), 7=stay 1
/* REG 13 */
__MREG__(MAX2837_HPC_100K,13,1,2) // steps of 3.2uS (0.0-9.6)
__MREG__(MAX2837_HPC_100K_GAIN,13,3,2) // steps of 3.2uS (0.0-9.6)
__MREG__(MAX2837_HPC_30K,13,5,2) // steps of 3.2uS (0.0-9.6)
__MREG__(MAX2837_HPC_30K_GAIN,13,7,2) // steps of 3.2uS (0.0-9.6)
__MREG__(MAX2837_HPC_1K,13,9,2) // steps of 3.2uS (0.0-9.6)
/* REG 14 */
__MREG__(MAX2837_HPC_1K_GAIN,14,1,2) // steps of 3.2uS (0.0-9.6)
__MREG__(MAX2837_HPC_DELAY,14,3,2) // steps of 0.2uS (0.0-0.6)
__MREG__(MAX2837_HPC_STOP,14,5,2)
#define MAX2837_STOP_100 0
#define MAX2837_STOP_1K 1
#define MAX2837_STOP_30K 2
#define MAX2837_STOP_100K 3
__MREG__(MAX2837_HPC_STOP_M2,14,7,2)
#define MAX2837_STOP_M2_1K 0
#define MAX2837_STOP_M2_30K 1
#define MAX2837_STOP_M2_100K 2
#define MAX2837_STOP_M2_600K 3
__MREG__(MAX2837_HPC_RXGAIN_EN,14,8,1) // RXVGA HPFSM re-triggered by B7 & B6
__MREG__(MAX2837_HPC_MODE,14,9,1) // use RXHP
/* REG 15 */
__MREG__(MAX2837_HPC_DIVH,15,0,1)
#define MAX2837_HPC_DIVH_20M 0
#define MAX2837_HPC_DIVH_40M 1
__MREG__(MAX2837_HPC_TST,15,5,5) // filter test modes ... see doc
__MREG__(MAX2837_HPC_SEQ_BYP,15,6,1) // set to bypass programmed sequence
__MREG__(MAX2837_DOUT_CSB_SEL,15,7,1) // set to tri state DOUT when CSB high
/* REG 16 */
__MREG__(MAX2837_EN_SPI,16,0,1) // enable overall chip
__MREG__(MAX2837_CAL_SPI,16,1,1) // enable calibration mode
__MREG__(MAX2837_LOGEN_SPI_EN,16,2,1) // ???
__MREG__(MAX2837_SYN_SPI_EN,16,3,1) // enable synthesizer
__MREG__(MAX2837_VAS_SPI_EN,16,4,1) // enable VCO autoselect
__MREG__(MAX2837_PADRV_SPI_EN,16,5,1) // enable power amp
__MREG__(MAX2837_PADAC_SPI_EN,16,6,1) // enable power amp bias DAC always
__MREG__(MAX2837_PADAC_TX_EN,16,7,1) // enable power amp bias only if TX pin
__MREG__(MAX2837_TXMX_SPI_EN,16,8,1) // enable TX mixer
__MREG__(MAX2837_TXLO_SPI_EN,16,9,1) // enable TX LO
/* REG 17 */
__MREG__(MAX2837_SYN_FRAC_LO,17,9,10)
/* REG 18 */
__MREG__(MAX2837_SYN_FRAC_HI,18,9,10)
/* REG 19 */
__MREG__(MAX2837_SYN_INT,19,7,8)
__MREG__(MAX2837_LOGEN_BSW,19,9,2)
#define MAX2837_LOGEN_BSW_2_3 0 // 2300 - <2400 MHz
#define MAX2837_LOGEN_BSW_2_4 1 // 2400 - <2500 MHz
#define MAX2837_LOGEN_BSW_2_5 2 // 2500 - <2600 MHz
#define MAX2837_LOGEN_BSW_2_6 3 // 2600 - <2700 MHz
/* REG 20 */
__MREG__(MAX2837_SYN_MODE,20,0,1)
#define MAX2837_SYN_MODE_INTEGER 0
#define MAX2837_SYN_MODE_FRACTIONAL 1
__MREG__(MAX2837_SYN_REF_DIV,20,2,2)
#define MAX2837_SYN_REF_DIV_1 0
#define MAX2837_SYN_REF_DIV_2 1
#define MAX2837_SYN_REF_DIV_4 2
#define MAX2837_SYN_REF_DIV_8 3
__MREG__(MAX2837_SYN_CURRENT_,20,4,2)
#define MAX2837_SYN_CURRENT_3_2_DIFF 0 // 3.2mA differential
#define MAX2837_SYN_CURRENT_1_6_DIFF 1 // 1.6mA differential
#define MAX2837_SYN_CURRENT_1_6_SINGLE 2 // 1.6mA single-ended
#define MAX2837_SYN_CURRENT_0_8_SINGLE 3 // 0.8mA single-ended
__MREG__(MAX2837_SYN_CLOCKOUT_DRIVE,20,5,1)
#define MAX2837_SYN_CLOCKOUT_DRIVE_1X 0
#define MAX2837_SYN_CLOCKOUT_DRIVE_4X 1
__MREG__(MAX2837_SYN_TURBO_EN,20,6,1) // ???
__MREG__(MAX2837_SYN_BIAS_SPI,20,7,1) // Use trim value below
__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,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
__MREG__(MAX2837_SYN_CP_PULSE_WIDTH_ADJ,21,4,1) // 0=default 1=-20%
__MREG__(MAX2837_SYN_CP_LIN_CUR,21,6,2) // +3% per step
__MREG__(MAX2837_SYN_TEST_OUT,21,9,3) // high bit locks CP in test mode
#define MAX2837_SYN_TEST_LOCK_DETECT 0b000
#define MAX2837_SYN_TEST_SD 0b001
#define MAX2837_SYN_TEST_REF_DIV 0b010
#define MAX2837_SYN_TEST_MAIN_DIV 0b011
#define MAX2837_SYN_TEST_CP_LO_Z_LOCK_DETECT 0b100
#define MAX2837_SYN_TEST_CP_SOURCE_SD 0b101
#define MAX2837_SYN_TEST_CP_SINK_REF_DIV 0b110
#define MAX2837_SYN_TEST_CP_HI_Z_MAIN_DIV 0b111
/* REG 22 */
__MREG__(MAX2837_VAS_EN,22,0,1) // select VCO subband by VAS, vs. reg
__MREG__(MAX2837_VAS_RELOCK_SEL,22,1,1)
#define MAX2837_VAS_RELOCK_SELECTED 0
#define MAX2837_VAS_RELOCK_PRESENT 1
__MREG__(MAX2837_VAS_DIV,22,4,3)
#define MAX2837_VAS_CLK_DIV_8 0
#define MAX2837_VAS_CLK_DIV_9 1
#define MAX2837_VAS_CLK_DIV_10 2
#define MAX2837_VAS_CLK_DIV_11 3
#define MAX2837_VAS_CLK_DIV_12 4
#define MAX2837_VAS_CLK_DIV_13 5
#define MAX2837_VAS_CLK_DIV_14 6
#define MAX2837_VAS_CLK_DIV_2 7
__MREG__(MAX2837_VAS_DLY,22,6,2) // Delay = Txtal * VAS_DIV * VAS_DLY * 7
#define MAX2837_VAS_DLY_16
#define MAX2837_VAS_DLY_32
#define MAX2837_VAS_DLY_64
#define MAX2837_VAS_DLY_128
__MREG__(MAX2837_VAS_TRIG_EN,22,7,1)
__MREG__(MAX2837_VAS_ADE,22,8,1)
__MREG__(MAX2837_VAS_ADL_SPI,22,9,1)
/* REG 23 */
__MREG__(MAX2837_VAS_SPI,23,4,5) // subband selection default is center (15)
__MREG__(MAX2837_XTAL_BIAS,23,6,2)
#define MAX2837_XTAL_BIAS_240_20 0 // 240uA for 20MHz
#define MAX2837_XTAL_BIAS_420_20 1
#define MAX2837_XTAL_BIAS_600_40 2
#define MAX2837_XTAL_BIAS_780_40 3
__MREG__(MAX2837_XTAL_E2C_BIAS,23,7,1)
#define MAX2837_XTAL_E2C_BIAS_360 0 // uA
#define MAX2837_XTAL_E2C_BIAS_540 1
__MREG__(MAX2837_VAS_SE,23,8,1)
#define MAX2837_VAS_SE_DIFF 0
#define MAX2837_VAS_SE_SINGLE 1
__MREG__(MAX2837_VCO_SPI_EN,23,9,1) // set to override mode
/* REG 24 */
__MREG__(MAX2837_XTAL_TUNE,24,6,7) // 0=max 127=min freq
__MREG__(MAX2837_CLKOUT_PIN_EN,24,7,1)
__MREG__(MAX2837_CLKOUT_DIV,24,8,1)
#define MAX2837_CLKOUT_DIV_1 0
#define MAX2837_CLKOUT_DIV_2 1
__MREG__(MAX2837_XTAL_CORE_EN,24,9,1) // set to override mode
/* REG 25 */
__MREG__(MAX2837_VCO_BIAS_SPI_EN,25,0,1) // enable override of vco bias trim
__MREG__(MAX2837_VCO_BIAS,25,4,4) // 0b1000 nominal
__MREG__(MAX2837_VCO_CMEN,25,5,1) // enable Miller capacitor
__MREG__(MAX2837_VCO_PDET_TST,25,7,2) // peak detector test output select
#define MAX2837_VCO_PDET_TST_NORMAL 0
#define MAX2837_VCO_PDET_TST_PDOUT 1 // peak detector output
#define MAX2837_VCO_PDET_TST_PDREF 2 // peak detector reference
#define MAX2837_VCO_PDET_TST_TEMP 3 // VCO temperature sensor
__MREG__(MAX2837_VCO_BUF_BIAS,25,9,2) // VCO buffer bias
#define MAX2837_VCO_BUF_BIAS_800uA 0
#define MAX2837_VCO_BUF_BIAS_1200uA 1 // default
#define MAX2837_VCO_BUF_BIAS_1600uA 2
#define MAX2837_VCO_BUF_BIAS_2000uA 3
/* REG 26 */
__MREG__(MAX2837_LOGEN_BIAS1,26,1,2) // LOGEN emitter follower bias
#define MAX2837_LOGEN_BIAS1_400u 0
#define MAX2837_LOGEN_BIAS1_600u 1
#define MAX2837_LOGEN_BIAS1_800u 2
#define MAX2837_LOGEN_BIAS1_1000u 3
__MREG__(MAX2837_LOGEN_BIAS2,26,2,1) // LOGEN RX/TX Gm bias
#define MAX2837_LOGEN_BIAS2_DEFAULT 0 // default
#define MAX2837_LOGEN_BIAS2_PLUS25 1 // +25%
__MREG__(MAX2837_LOGEN_2GM,26,3,1) //
__MREG__(MAX2837_LOGEN_TRIM1,26,4,1) // mixer tank trim enable
__MREG__(MAX2837_LOGEN_TRIM2,26,5,1) // bandpass filter trim enable
__MREG__(MAX2837_VAS_TST,26,9,4) // DOUT test signal select
#define MAX2837_VAS_TST_VCO_BSW0 0 // VAS band select output (5 bits)
#define MAX2837_VAS_TST_VCO_BSW1 1
#define MAX2837_VAS_TST_VCO_BSW2 2
#define MAX2837_VAS_TST_VCO_BSW3 3
#define MAX2837_VAS_TST_VCO_BSW4 4
#define MAX2837_VAS_TST_Vtune_ADC0 5 // VCO Vtune ADC output (3 bits)
#define MAX2837_VAS_TST_Vtune_ADC1 6
#define MAX2837_VAS_TST_Vtune_ADC2 7
#define MAX2837_VAS_TST_VASA 8 // VAS accomplish (success)
#define MAX2837_VAS_TST_VASE 9 // VAS end (success or gave up)
#define MAX2837_VAS_TST_ZERO 15 // default
/* REG 27 */
__MREG__(MAX2837_PADRV_BIAS,27,2,3) // PA driver bias (0-7), default 3
__MREG__(MAX2837_PADRV_DOWN_SPI_EN,27,3,1) // PA drv down process select enable
__MREG__(MAX2837_PADRV_DOWN,27,4,1) // PA driver down select
#define MAX2837_PADRV_DOWN_DOWN 0
#define MAX2837_PADRV_DOWN_UP 1 // default
__MREG__(MAX2837_PADAC_IV,27,5,1) // PA DAC I/V output select
#define MAX2837_PADAC_IV_VOLTAGE 0
#define MAX2837_PADAC_IV_CURRENT 1 // default
__MREG__(MAX2837_PADAC_VMODE,27,6,1) // set logic 0 or 1 for PADAC_IV out
__MREG__(MAX2837_PADAC_DIV,27,7,1) // PA DAC clock divide ratio
#define MAX2837_PADAC_DIV_20MHz 0
#define MAX2837_PADAC_DIV_40MHz 1
__MREG__(MAX2837_TXGATE_EN,27,8,1) // set to relock when TXOOL=1 or LD=0
__MREG__(MAX2837_TXDCCORR_EN,27,9,1) // TX DC offset correction enable
/* REG 28 */
__MREG__(MAX2837_PADAC_BIAS,28,5,6) // PADAC output current control, 5uA step
__MREG__(MAX2837_PADAC_DLY,28,9,4) // PADAC turn-on delay control
// 0,1 are both 0us
// then 0.5us steps to 7.0us
/* REG 29 */
__MREG__(MAX2837_TXVGA_GAIN_SPI_EN,29,0,1) // Enable SPI control of TXVGA gain
__MREG__(MAX2837_TXVGA_GAIN_MSB_SPI_EN,29,1,1)
__MREG__(MAX2837_TX_DCCORR_SPI_EN,29,2,1)
__MREG__(MAX2837_FUSE_ARM,29,3,1) // Fuse burn enable
__MREG__(MAX2837_TXVGA_GAIN,29,9,6) // 0 = min atten, 63 = max atten
/* REG 30 */
__MREG__(MAX2837_TXLO_IQ,30,4,5)
__MREG__(MAX2837_TXLO_IQ_SPI_EN,30,5,1)
__MREG__(MAX2837_TXLO_BUFF_BIAS,30,7,2)
#define MAX2837_TXLO_BUFF_BIAS_1_0mA 0
#define MAX2837_TXLO_BUFF_BIAS_1_5mA 1
#define MAX2837_TXLO_BUFF_BIAS_2_0mA 2 // default
#define MAX2837_TXLO_BUFF_BIAS_2_5mA 3
__MREG__(MAX2837_FUSE_GKT,30,8,1)
__MREG__(MAX2837_FUSE_RTH,30,9,1)
/* REG 31 */
// 0 -> 992/0uA correction, 15 -> 0/992uA correction ... if TX_DCCORR_SPI_EN
__MREG__(MAX2837_TX_DCCORR_I,31,4,5)
__MREG__(MAX2837_TX_DCCORR_Q,31,9,5)
#endif // __MAX2837_REGS_DEF

View File

@ -0,0 +1,74 @@
/*
* Copyright 2012 Will Code? (TODO: Proper attribution)
* Copyright 2014 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 "max2837_target.h"
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h"
void max2837_target_init(max2837_driver_t* const drv) {
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */
scu_pinmux(SCU_SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
scu_pinmux(SCU_XCVR_CS, SCU_GPIO_FAST);
/* Configure XCVR_CTL GPIO pins. */
scu_pinmux(SCU_XCVR_ENABLE, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_RXENABLE, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_TXENABLE, SCU_GPIO_FAST);
/* Set GPIO pins as outputs. */
gpio_output(drv->gpio_enable);
gpio_output(drv->gpio_rx_enable);
gpio_output(drv->gpio_tx_enable);
}
void max2837_target_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode) {
/* MAX2837_MODE_SHUTDOWN:
* All circuit blocks are powered down, except the 4-wire serial bus
* and its internal programmable registers.
*
* MAX2837_MODE_STANDBY:
* 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.
*
* MAX2837_MODE_TX:
* 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.
*
* MAX2837_MODE_RX:
* 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_write(drv->gpio_enable, new_mode != MAX2837_MODE_SHUTDOWN);
gpio_write(drv->gpio_rx_enable, new_mode == MAX2837_MODE_RX);
gpio_write(drv->gpio_tx_enable, new_mode == MAX2837_MODE_TX);
drv->mode = new_mode;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2012 Will Code? (TODO: Proper attribution)
* Copyright 2014 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 __MAX2837_TARGET_H
#define __MAX2837_TARGET_H
#include "max2837.h"
void max2837_target_init(max2837_driver_t* const drv);
void max2837_target_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode);
#endif // __MAX2837_TARGET_H

View File

@ -0,0 +1,236 @@
#include "max2871.h"
#include "max2871_regs.h"
#if (defined DEBUG)
#include <stdio.h>
#define LOG printf
#else
#define LOG(x,...)
#include <libopencm3/lpc43xx/ssp.h>
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h"
#endif
#include <stdint.h>
#include <string.h>
static void max2871_spi_write(max2871_driver_t* const drv, uint8_t r, uint32_t v);
static void max2871_write_registers(max2871_driver_t* const drv);
static void delay_ms(int ms);
void max2871_setup(max2871_driver_t* const drv)
{
/* Configure GPIO pins. */
scu_pinmux(SCU_VCO_CE, SCU_GPIO_FAST);
scu_pinmux(SCU_VCO_SCLK, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
/* Only used for the debug pin config: scu_pinmux(SCU_VCO_SCLK, SCU_GPIO_FAST); */
scu_pinmux(SCU_VCO_SDATA, SCU_GPIO_FAST);
scu_pinmux(SCU_VCO_LE, SCU_GPIO_FAST);
scu_pinmux(SCU_VCO_MUX, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_SYNT_RFOUT_EN, SCU_GPIO_FAST);
/* Set GPIO pins as outputs. */
gpio_output(drv->gpio_vco_ce);
gpio_output(drv->gpio_vco_sclk);
gpio_output(drv->gpio_vco_sdata);
gpio_output(drv->gpio_vco_le);
gpio_output(drv->gpio_synt_rfout_en);
/* MUX is an input */
gpio_input(drv->gpio_vco_mux);
/* set to known state */
gpio_set(drv->gpio_vco_ce); /* active high */
gpio_clear(drv->gpio_vco_sclk);
gpio_clear(drv->gpio_vco_sdata);
gpio_set(drv->gpio_vco_le); /* active low */
gpio_set(drv->gpio_synt_rfout_en); /* active high */
max2871_regs_init();
int i;
for(i = 5; i >= 0; i--) {
max2871_spi_write(drv, i, max2871_get_register(i));
delay_ms(20);
}
max2871_set_INT(1);
max2871_set_N(4500);
max2871_set_FRAC(0);
max2871_set_CPL(0);
max2871_set_CPT(0);
max2871_set_P(1);
max2871_set_M(0);
max2871_set_LDS(0);
max2871_set_SDN(0);
max2871_set_MUX(0x0C); /* Register 6 readback */
max2871_set_DBR(0);
max2871_set_RDIV2(0);
max2871_set_R(1); /* 40 MHz f_PFD */
max2871_set_REG4DB(1);
max2871_set_CP(15); /* ?: CP charge pump current 0-15 */
max2871_set_LDF(1); /* INT-N */
max2871_set_LDP(0); /* ?: Lock-Detect Precision */
max2871_set_PDP(1);
max2871_set_SHDN(0);
max2871_set_TRI(0);
max2871_set_RST(0);
max2871_set_VCO(0);
max2871_set_VAS_SHDN(0);
max2871_set_VAS_TEMP(1);
max2871_set_CSM(0);
max2871_set_MUTEDEL(1);
max2871_set_CDM(0);
max2871_set_CDIV(0);
max2871_set_SDLDO(0);
max2871_set_SDDIV(0);
max2871_set_SDREF(0);
max2871_set_BS(20*40); /* For 40 MHz f_PFD */
max2871_set_FB(1); /* Do not put DIVA into the feedback loop */
max2871_set_DIVA(0);
max2871_set_SDVCO(0);
max2871_set_MTLD(1);
max2871_set_BDIV(0);
max2871_set_RFB_EN(0);
max2871_set_BPWR(0);
max2871_set_RFA_EN(0);
max2871_set_APWR(3);
max2871_set_SDPLL(0);
max2871_set_F01(1);
max2871_set_LD(1);
max2871_set_ADCS(0);
max2871_set_ADCM(0);
max2871_write_registers(drv);
max2871_set_frequency(drv, 3500);
}
static void delay_ms(int ms)
{
uint32_t i;
while(ms--) {
for (i = 0; i < 20000; i++) {
__asm__("nop");
}
}
}
static void serial_delay(void)
{
uint32_t i;
for (i = 0; i < 2; i++)
__asm__("nop");
}
/* SPI register write
*
* Send 32 bits:
* First 29 bits are data
* Last 3 bits are register number */
static void max2871_spi_write(max2871_driver_t* const drv, uint8_t r, uint32_t v) {
#if DEBUG
LOG("0x%04x -> reg%d\n", v, r);
#else
uint32_t bits = 32;
uint32_t msb = 1 << (bits -1);
uint32_t data = v | r;
/* make sure everything is starting in the correct state */
gpio_set(drv->gpio_vco_le);
gpio_clear(drv->gpio_vco_sclk);
gpio_clear(drv->gpio_vco_sdata);
/* start transaction by bringing LE low */
gpio_clear(drv->gpio_vco_le);
while (bits--) {
if (data & msb)
gpio_set(drv->gpio_vco_sdata);
else
gpio_clear(drv->gpio_vco_sdata);
data <<= 1;
serial_delay();
gpio_set(drv->gpio_vco_sclk);
serial_delay();
gpio_clear(drv->gpio_vco_sclk);
}
gpio_set(drv->gpio_vco_le);
#endif
}
static uint32_t max2871_spi_read(max2871_driver_t* const drv)
{
uint32_t bits = 32;
uint32_t data = 0;
max2871_spi_write(drv, 0x06, 0x0);
serial_delay();
gpio_set(drv->gpio_vco_sclk);
serial_delay();
gpio_clear(drv->gpio_vco_sclk);
serial_delay();
while (bits--) {
gpio_set(drv->gpio_vco_sclk);
serial_delay();
gpio_clear(drv->gpio_vco_sclk);
serial_delay();
data <<= 1;
data |= gpio_read(drv->gpio_vco_mux) ? 1 : 0;
}
return data;
}
static void max2871_write_registers(max2871_driver_t* const drv)
{
int i;
for(i = 5; i >= 0; i--) {
max2871_spi_write(drv, i, max2871_get_register(i));
}
}
/* Set frequency (MHz). */
uint64_t max2871_set_frequency(max2871_driver_t* const drv, uint16_t mhz)
{
int n = mhz / 40;
int diva = 0;
while(n * 40 < 3000) {
n *= 2;
diva += 1;
}
max2871_set_RFA_EN(0);
max2871_write_registers(drv);
max2871_set_N(n);
max2871_set_DIVA(diva);
max2871_write_registers(drv);
while(max2871_spi_read(drv) & MAX2871_VASA);
max2871_set_RFA_EN(1);
max2871_write_registers(drv);
return (mhz/40)*40 * 1000000;
}
void max2871_enable(max2871_driver_t* const drv)
{
gpio_set(drv->gpio_vco_ce);
}
void max2871_disable(max2871_driver_t* const drv)
{
gpio_clear(drv->gpio_vco_ce);
}

View File

@ -0,0 +1,21 @@
#ifndef MAX2871_H
#define MAX2871_H
#include "gpio.h"
#include <stdint.h>
typedef struct {
gpio_t gpio_vco_ce;
gpio_t gpio_vco_sclk;
gpio_t gpio_vco_sdata;
gpio_t gpio_vco_le;
gpio_t gpio_synt_rfout_en;
gpio_t gpio_vco_mux;
} max2871_driver_t;
extern void max2871_setup(max2871_driver_t* const drv);
extern uint64_t max2871_set_frequency(max2871_driver_t* const drv, uint16_t mhz);
extern void max2871_enable(max2871_driver_t* const drv);
extern void max2871_disable(max2871_driver_t* const drv);
#endif

View File

@ -0,0 +1,299 @@
#include "max2871_regs.h"
#include <stdint.h>
static uint32_t registers[6];
void max2871_regs_init(void)
{
registers[0] = 0x007D0000;
registers[1] = 0x2000FFF9;
registers[2] = 0x00004042;
registers[3] = 0x0000000B;
registers[4] = 0x6180B23C;
registers[5] = 0x00400005;
}
uint32_t max2871_get_register(int reg)
{
return registers[reg];
}
void max2871_set_INT(uint32_t v)
{
registers[0] &= ~(0x1 << 31);
registers[0] |= v << 31;
}
void max2871_set_N(uint32_t v)
{
registers[0] &= ~(0xFFFF << 15);
registers[0] |= v << 15;
}
void max2871_set_FRAC(uint32_t v)
{
registers[0] &= ~(0xFFF << 3);
registers[0] |= v << 3;
}
void max2871_set_CPL(uint32_t v)
{
registers[1] &= ~(0x3 << 29);
registers[1] |= v << 29;
}
void max2871_set_CPT(uint32_t v)
{
registers[1] &= ~(0x3 << 27);
registers[1] |= v << 27;
}
void max2871_set_P(uint32_t v)
{
registers[1] &= ~(0xFFF << 15);
registers[1] |= v << 15;
}
void max2871_set_M(uint32_t v)
{
registers[1] &= ~(0xFFF << 3);
registers[1] |= v << 3;
}
void max2871_set_LDS(uint32_t v)
{
registers[2] &= ~(0x1 << 31);
registers[2] |= v << 31;
}
void max2871_set_SDN(uint32_t v)
{
registers[2] &= ~(0x3 << 29);
registers[2] |= v << 29;
}
void max2871_set_MUX(uint32_t v)
{
registers[2] &= ~(0x7 << 26);
registers[5] &= ~(0x1 << 18);
registers[2] |= (v & 0x7) << 26;
registers[5] |= ((v & 0x8) >> 3) << 18;
}
void max2871_set_DBR(uint32_t v)
{
registers[2] &= ~(0x1 << 25);
registers[2] |= v << 25;
}
void max2871_set_RDIV2(uint32_t v)
{
registers[2] &= ~(0x1 << 24);
registers[2] |= v << 24;
}
void max2871_set_R(uint32_t v)
{
registers[2] &= ~(0x3FF << 14);
registers[2] |= v << 14;
}
void max2871_set_REG4DB(uint32_t v)
{
registers[2] &= ~(0x1 << 13);
registers[2] |= v << 13;
}
void max2871_set_CP(uint32_t v)
{
registers[2] &= ~(0xF << 9);
registers[2] |= v << 9;
}
void max2871_set_LDF(uint32_t v)
{
registers[2] &= ~(0x1 << 8);
registers[2] |= v << 8;
}
void max2871_set_LDP(uint32_t v)
{
registers[2] &= ~(0x1 << 7);
registers[2] |= v << 7;
}
void max2871_set_PDP(uint32_t v)
{
registers[2] &= ~(0x1 << 6);
registers[2] |= v << 6;
}
void max2871_set_SHDN(uint32_t v)
{
registers[2] &= ~(0x1 << 5);
registers[2] |= v << 5;
}
void max2871_set_TRI(uint32_t v)
{
registers[2] &= ~(0x1 << 4);
registers[2] |= v << 4;
}
void max2871_set_RST(uint32_t v)
{
registers[2] &= ~(0x1 << 3);
registers[2] |= v << 3;
}
void max2871_set_VCO(uint32_t v)
{
registers[3] &= ~(0x3F << 26);
registers[3] |= v << 26;
}
void max2871_set_VAS_SHDN(uint32_t v)
{
registers[3] &= ~(0x1 << 25);
registers[3] |= v << 25;
}
void max2871_set_VAS_TEMP(uint32_t v)
{
registers[3] &= ~(0x1 << 24);
registers[3] |= v << 24;
}
void max2871_set_CSM(uint32_t v)
{
registers[3] &= ~(0x1 << 18);
registers[3] |= v << 18;
}
void max2871_set_MUTEDEL(uint32_t v)
{
registers[3] &= ~(0x1 << 17);
registers[3] |= v << 17;
}
void max2871_set_CDM(uint32_t v)
{
registers[3] &= ~(0x3 << 15);
registers[3] |= v << 15;
}
void max2871_set_CDIV(uint32_t v)
{
registers[3] &= ~(0xFFF << 3);
registers[3] |= v << 3;
}
void max2871_set_SDLDO(uint32_t v)
{
registers[4] &= ~(0x1 << 28);
registers[4] |= v << 28;
}
void max2871_set_SDDIV(uint32_t v)
{
registers[4] &= ~(0x1 << 27);
registers[4] |= v << 27;
}
void max2871_set_SDREF(uint32_t v)
{
registers[4] &= ~(0x1 << 26);
registers[4] |= v << 26;
}
void max2871_set_BS(uint32_t v)
{
registers[4] &= ~(0x3 << 24);
registers[4] &= ~(0xFF << 12);
registers[4] |= ((v & 0x300) >> 8) << 24;
registers[4] |= (v & 0xFF) << 12;
}
void max2871_set_FB(uint32_t v)
{
registers[4] &= ~(0x1 << 23);
registers[4] |= v << 23;
}
void max2871_set_DIVA(uint32_t v)
{
registers[4] &= ~(0x7 << 20);
registers[4] |= v << 20;
}
void max2871_set_SDVCO(uint32_t v)
{
registers[4] &= ~(0x1 << 11);
registers[4] |= v << 11;
}
void max2871_set_MTLD(uint32_t v)
{
registers[4] &= ~(0x1 << 10);
registers[4] |= v << 10;
}
void max2871_set_BDIV(uint32_t v)
{
registers[4] &= ~(0x1 << 9);
registers[4] |= v << 9;
}
void max2871_set_RFB_EN(uint32_t v)
{
registers[4] &= ~(0x1 << 8);
registers[4] |= v << 8;
}
void max2871_set_BPWR(uint32_t v)
{
registers[4] &= ~(0x3 << 6);
registers[4] |= v << 6;
}
void max2871_set_RFA_EN(uint32_t v)
{
registers[4] &= ~(0x1 << 5);
registers[4] |= v << 5;
}
void max2871_set_APWR(uint32_t v)
{
registers[4] &= ~(0x3 << 3);
registers[4] |= v << 3;
}
void max2871_set_SDPLL(uint32_t v)
{
registers[5] &= ~(0x1 << 25);
registers[5] |= v << 25;
}
void max2871_set_F01(uint32_t v)
{
registers[5] &= ~(0x1 << 24);
registers[5] |= v << 24;
}
void max2871_set_LD(uint32_t v)
{
registers[5] &= ~(0x3 << 22);
registers[5] |= v << 22;
}
void max2871_set_ADCS(uint32_t v)
{
registers[5] &= ~(0x1 << 6);
registers[5] |= v << 6;
}
void max2871_set_ADCM(uint32_t v)
{
registers[5] &= ~(0x7 << 3);
registers[5] |= v << 3;
}

View File

@ -0,0 +1,56 @@
#ifndef MAX2871_REGS_H
#define MAX2871_REGS_H
#include <stdint.h>
#define MAX2871_VASA (1 << 9)
void max2871_regs_init(void);
uint32_t max2871_get_register(int reg);
void max2871_set_INT(uint32_t v);
void max2871_set_N(uint32_t v);
void max2871_set_FRAC(uint32_t v);
void max2871_set_CPL(uint32_t v);
void max2871_set_CPT(uint32_t v);
void max2871_set_P(uint32_t v);
void max2871_set_M(uint32_t v);
void max2871_set_LDS(uint32_t v);
void max2871_set_SDN(uint32_t v);
void max2871_set_MUX(uint32_t v);
void max2871_set_DBR(uint32_t v);
void max2871_set_RDIV2(uint32_t v);
void max2871_set_R(uint32_t v);
void max2871_set_REG4DB(uint32_t v);
void max2871_set_CP(uint32_t v);
void max2871_set_LDF(uint32_t v);
void max2871_set_LDP(uint32_t v);
void max2871_set_PDP(uint32_t v);
void max2871_set_SHDN(uint32_t v);
void max2871_set_TRI(uint32_t v);
void max2871_set_RST(uint32_t v);
void max2871_set_VCO(uint32_t v);
void max2871_set_VAS_SHDN(uint32_t v);
void max2871_set_VAS_TEMP(uint32_t v);
void max2871_set_CSM(uint32_t v);
void max2871_set_MUTEDEL(uint32_t v);
void max2871_set_CDM(uint32_t v);
void max2871_set_CDIV(uint32_t v);
void max2871_set_SDLDO(uint32_t v);
void max2871_set_SDDIV(uint32_t v);
void max2871_set_SDREF(uint32_t v);
void max2871_set_BS(uint32_t v);
void max2871_set_FB(uint32_t v);
void max2871_set_DIVA(uint32_t v);
void max2871_set_SDVCO(uint32_t v);
void max2871_set_MTLD(uint32_t v);
void max2871_set_BDIV(uint32_t v);
void max2871_set_RFB_EN(uint32_t v);
void max2871_set_BPWR(uint32_t v);
void max2871_set_RFA_EN(uint32_t v);
void max2871_set_APWR(uint32_t v);
void max2871_set_SDPLL(uint32_t v);
void max2871_set_F01(uint32_t v);
void max2871_set_LD(uint32_t v);
void max2871_set_ADCS(uint32_t v);
void max2871_set_ADCM(uint32_t v);
#endif

View File

@ -0,0 +1,102 @@
/*
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <stdint.h>
#include "max5864.h"
static void max5864_write(max5864_driver_t* const drv, uint8_t value) {
spi_bus_transfer(drv->bus, &value, 1);
}
static void max5864_init(max5864_driver_t* const drv) {
drv->target_init(drv);
}
void max5864_setup(max5864_driver_t* const drv) {
max5864_init(drv);
}
/* Set MAX5864 operation mode to "Shutdown":
* REF: off
* CLK: off
* ADCs: off (bus is tri-stated)
* DACs: off (set input bus to zero or OVdd)
*/
void max5864_shutdown(max5864_driver_t* const drv)
{
max5864_write(drv, 0x00);
}
/* Set MAX5864 operation mode to "Standby":
* REF: on
* CLK: off?
* ADCs: off (bus is tri-stated)
* DACs: off (set input bus to zero or OVdd)
*/
void max5864_standby(max5864_driver_t* const drv)
{
max5864_write(drv, 0x05);
}
/* Set MAX5864 operation mode to "Idle":
* REF: on
* CLK: on
* ADCs: off (bus is tri-stated)
* DACs: off (set input bus to zero or OVdd)
*/
void max5864_idle(max5864_driver_t* const drv)
{
max5864_write(drv, 0x01);
}
/* Set MAX5864 operation mode to "Rx":
* REF: on
* CLK: on
* ADCs: on
* DACs: off (set input bus to zero or OVdd)
*/
void max5864_rx(max5864_driver_t* const drv)
{
max5864_write(drv, 0x02);
}
/* Set MAX5864 operation mode to "Tx":
* REF: on
* CLK: on
* ADCs: off (bus is tri-stated)
* DACs: on
*/
void max5864_tx(max5864_driver_t* const drv)
{
max5864_write(drv, 0x03);
}
/* Set MAX5864 operation mode to "Xcvr":
* REF: on
* CLK: on
* ADCs: on
* DACs: on
*/
void max5864_xcvr(max5864_driver_t* const drv)
{
max5864_write(drv, 0x04);
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __MAX5864_H
#define __MAX5864_H
#include "spi_bus.h"
struct max5864_driver_t;
typedef struct max5864_driver_t max5864_driver_t;
struct max5864_driver_t {
spi_bus_t* const bus;
void (*target_init)(max5864_driver_t* const drv);
};
void max5864_setup(max5864_driver_t* const drv);
void max5864_shutdown(max5864_driver_t* const drv);
void max5864_standby(max5864_driver_t* const drv);
void max5864_idle(max5864_driver_t* const drv);
void max5864_rx(max5864_driver_t* const drv);
void max5864_tx(max5864_driver_t* const drv);
void max5864_xcvr(max5864_driver_t* const drv);
#endif // __MAX5864_H

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 "max5864_target.h"
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h"
void max5864_target_init(max5864_driver_t* const drv) {
(void)drv;
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */
scu_pinmux(SCU_SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
/*
* Configure CS_AD pin to keep the MAX5864 SPI disabled while we use the
* SPI bus for the MAX2837. FIXME: this should probably be somewhere else.
*/
scu_pinmux(SCU_AD_CS, SCU_GPIO_FAST);
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 __MAX5864_TARGET_H__
#define __MAX5864_TARGET_H__
#include "max5864.h"
void max5864_target_init(max5864_driver_t* const drv);
#endif/*__MAX5864_TARGET_H__*/

View File

@ -0,0 +1,144 @@
#include "mixer.h"
#include "rffc5071.h"
#include "rffc5071_spi.h"
#include "max2871.h"
#include "gpio_lpc.h"
/* RFFC5071 GPIO serial interface PinMux */
#if (defined JAWBREAKER || defined HACKRF_ONE)
static struct gpio_t gpio_rffc5072_select = GPIO(2, 13);
static struct gpio_t gpio_rffc5072_clock = GPIO(5, 6);
static struct gpio_t gpio_rffc5072_data = GPIO(3, 3);
static struct gpio_t gpio_rffc5072_reset = GPIO(2, 14);
#endif
#ifdef RAD1O
static struct gpio_t gpio_vco_ce = GPIO(2, 13);
static struct gpio_t gpio_vco_sclk = GPIO(5, 6);
static struct gpio_t gpio_vco_sdata = GPIO(3, 3);
static struct gpio_t gpio_vco_le = GPIO(2, 14);
static struct gpio_t gpio_vco_mux = GPIO(5, 25);
static struct gpio_t gpio_synt_rfout_en = GPIO(3, 5);
#endif
#if (defined JAWBREAKER || defined HACKRF_ONE)
const rffc5071_spi_config_t rffc5071_spi_config = {
.gpio_select = &gpio_rffc5072_select,
.gpio_clock = &gpio_rffc5072_clock,
.gpio_data = &gpio_rffc5072_data,
};
spi_bus_t spi_bus_rffc5071 = {
.config = &rffc5071_spi_config,
.start = rffc5071_spi_start,
.stop = rffc5071_spi_stop,
.transfer = rffc5071_spi_transfer,
.transfer_gather = rffc5071_spi_transfer_gather,
};
mixer_driver_t mixer = {
.bus = &spi_bus_rffc5071,
.gpio_reset = &gpio_rffc5072_reset,
};
#endif
#ifdef RAD1O
mixer_driver_t mixer = {
.gpio_vco_ce = &gpio_vco_ce,
.gpio_vco_sclk = &gpio_vco_sclk,
.gpio_vco_sdata = &gpio_vco_sdata,
.gpio_vco_le = &gpio_vco_le,
.gpio_synt_rfout_en = &gpio_synt_rfout_en,
.gpio_vco_mux = &gpio_vco_mux,
};
#endif
void mixer_bus_setup(mixer_driver_t* const mixer)
{
#if (defined JAWBREAKER || defined HACKRF_ONE)
(void) mixer;
spi_bus_start(&spi_bus_rffc5071, &rffc5071_spi_config);
#endif
#ifdef RAD1O
(void) mixer;
#endif
}
void mixer_setup(mixer_driver_t* const mixer)
{
#if (defined JAWBREAKER || defined HACKRF_ONE)
rffc5071_setup(mixer);
#endif
#ifdef RAD1O
max2871_setup(mixer);
#endif
}
uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint16_t mhz)
{
#if (defined JAWBREAKER || defined HACKRF_ONE)
return rffc5071_set_frequency(mixer, mhz);
#endif
#ifdef RAD1O
return max2871_set_frequency(mixer, mhz);
#endif
}
void mixer_tx(mixer_driver_t* const mixer)
{
#if (defined JAWBREAKER || defined HACKRF_ONE)
rffc5071_tx(mixer);
#endif
#ifdef RAD1O
(void) mixer;
#endif
}
void mixer_rx(mixer_driver_t* const mixer)
{
#if (defined JAWBREAKER || defined HACKRF_ONE)
rffc5071_rx(mixer);
#endif
#ifdef RAD1O
(void) mixer;
#endif
}
void mixer_rxtx(mixer_driver_t* const mixer)
{
#if (defined JAWBREAKER || defined HACKRF_ONE)
rffc5071_rxtx(mixer);
#endif
#ifdef RAD1O
(void) mixer;
#endif
}
void mixer_enable(mixer_driver_t* const mixer)
{
#if (defined JAWBREAKER || defined HACKRF_ONE)
rffc5071_enable(mixer);
#endif
#ifdef RAD1O
max2871_enable(mixer);
#endif
}
void mixer_disable(mixer_driver_t* const mixer)
{
#if (defined JAWBREAKER || defined HACKRF_ONE)
rffc5071_disable(mixer);
#endif
#ifdef RAD1O
max2871_disable(mixer);
#endif
}
void mixer_set_gpo(mixer_driver_t* const mixer, uint8_t gpo)
{
#if (defined JAWBREAKER || defined HACKRF_ONE)
rffc5071_set_gpo(mixer, gpo);
#endif
#ifdef RAD1O
(void) mixer;
(void) gpo;
#endif
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2012 Michael Ossmann
* Copyright 2014 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 __MIXER_H
#define __MIXER_H
#if (defined JAWBREAKER || defined HACKRF_ONE)
#include "rffc5071.h"
typedef rffc5071_driver_t mixer_driver_t;
#endif
#ifdef RAD1O
#include "max2871.h"
typedef max2871_driver_t mixer_driver_t;
#endif
#include <stdint.h>
extern void mixer_bus_setup(mixer_driver_t* const mixer);
extern void mixer_setup(mixer_driver_t* const mixer);
/* Set frequency (MHz). */
extern uint64_t mixer_set_frequency(mixer_driver_t* const mixer, 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 mixer_tx(mixer_driver_t* const mixer);
extern void mixer_rx(mixer_driver_t* const mixer);
extern void mixer_rxtx(mixer_driver_t* const mixer);
extern void mixer_enable(mixer_driver_t* const mixer);
extern void mixer_disable(mixer_driver_t* const mixer);
extern void mixer_set_gpo(mixer_driver_t* const drv, uint8_t gpo);
#endif // __MIXER_H

View File

@ -0,0 +1,414 @@
/*
* Copyright 2016 Dominic Spill <dominicgs@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.
*/
#include "operacake.h"
#include "operacake_sctimer.h"
#include "hackrf_core.h"
#include "gpio.h"
#include "gpio_lpc.h"
#include "i2c_bus.h"
#include <libopencm3/lpc43xx/scu.h>
/*
* I2C Mode
*/
#define OPERACAKE_PIN_OE(x) (x<<7)
#define OPERACAKE_PIN_U2CTRL1(x) (x<<6)
#define OPERACAKE_PIN_U2CTRL0(x) (x<<5)
#define OPERACAKE_PIN_U3CTRL1(x) (x<<4)
#define OPERACAKE_PIN_U3CTRL0(x) (x<<3)
#define OPERACAKE_PIN_U1CTRL(x) (x<<2)
#define OPERACAKE_PIN_LEDEN2(x) (x<<1)
#define OPERACAKE_PIN_LEDEN(x) (x<<0)
#define OPERACAKE_PORT_A1 (OPERACAKE_PIN_U2CTRL0(0) | OPERACAKE_PIN_U2CTRL1(0))
#define OPERACAKE_PORT_A2 (OPERACAKE_PIN_U2CTRL0(1) | OPERACAKE_PIN_U2CTRL1(0))
#define OPERACAKE_PORT_A3 (OPERACAKE_PIN_U2CTRL0(0) | OPERACAKE_PIN_U2CTRL1(1))
#define OPERACAKE_PORT_A4 (OPERACAKE_PIN_U2CTRL0(1) | OPERACAKE_PIN_U2CTRL1(1))
#define OPERACAKE_PORT_B1 (OPERACAKE_PIN_U3CTRL0(0) | OPERACAKE_PIN_U3CTRL1(0))
#define OPERACAKE_PORT_B2 (OPERACAKE_PIN_U3CTRL0(1) | OPERACAKE_PIN_U3CTRL1(0))
#define OPERACAKE_PORT_B3 (OPERACAKE_PIN_U3CTRL0(0) | OPERACAKE_PIN_U3CTRL1(1))
#define OPERACAKE_PORT_B4 (OPERACAKE_PIN_U3CTRL0(1) | OPERACAKE_PIN_U3CTRL1(1))
#define OPERACAKE_SAMESIDE OPERACAKE_PIN_U1CTRL(1)
#define OPERACAKE_CROSSOVER OPERACAKE_PIN_U1CTRL(0)
#define OPERACAKE_EN_LEDS (OPERACAKE_PIN_LEDEN2(1) | OPERACAKE_PIN_LEDEN2(0))
#define OPERACAKE_GPIO_ENABLE OPERACAKE_PIN_OE(0)
#define OPERACAKE_GPIO_DISABLE OPERACAKE_PIN_OE(1)
#define OPERACAKE_REG_INPUT 0x00
#define OPERACAKE_REG_OUTPUT 0x01
#define OPERACAKE_REG_POLARITY 0x02
#define OPERACAKE_REG_CONFIG 0x03
#define OPERACAKE_DEFAULT_OUTPUT (OPERACAKE_GPIO_DISABLE | OPERACAKE_SAMESIDE \
| OPERACAKE_PORT_A1 | OPERACAKE_PORT_B1 \
| OPERACAKE_EN_LEDS)
#define OPERACAKE_CONFIG_ALL_OUTPUT (0x00)
// Leave LED bits as outputs
#define OPERACAKE_CONFIG_GPIO_INPUTS (0x7C)
#define OPERACAKE_POLARITY_NORMAL (0x00)
#define OPERACAKE_ADDRESS_DEFAULT 0x18
#define OPERACAKE_ADDRESS_INVALID 0xFF
#define OPERACAKE_MAX_BOARDS 8
#define INVALID_RANGE 0xFF;
static uint8_t current_range = INVALID_RANGE;
i2c_bus_t* const oc_bus = &i2c0;
enum operacake_switching_mode {
MODE_MANUAL = 0,
MODE_FREQUENCY = 1,
MODE_TIME = 2,
};
struct operacake_state {
bool present;
enum operacake_switching_mode mode;
uint8_t PA;
uint8_t PB;
};
struct operacake_state operacake_boards[OPERACAKE_MAX_BOARDS];
bool allow_gpio_mode = true;
/* read single register */
uint8_t operacake_read_reg(i2c_bus_t* const bus, uint8_t address, uint8_t reg) {
// Convert from Opera Cake address (0-7) to I2C address
address += OPERACAKE_ADDRESS_DEFAULT;
const uint8_t data_tx[] = { reg };
uint8_t data_rx[] = { 0x00 };
i2c_bus_transfer(bus, address, data_tx, 1, data_rx, 1);
return data_rx[0];
}
/* Write to one of the PCA9557 registers */
void operacake_write_reg(i2c_bus_t* const bus, uint8_t address, uint8_t reg, uint8_t value) {
// Convert from Opera Cake address (0-7) to I2C address
address += OPERACAKE_ADDRESS_DEFAULT;
const uint8_t data[] = {reg, value};
i2c_bus_transfer(bus, address, data, 2, NULL, 0);
}
uint8_t operacake_init(bool allow_gpio) {
/* Find connected operacakes */
for (int addr = 0; addr < 8; addr++) {
operacake_write_reg(oc_bus, addr, OPERACAKE_REG_OUTPUT,
OPERACAKE_DEFAULT_OUTPUT);
operacake_write_reg(oc_bus, addr, OPERACAKE_REG_CONFIG,
OPERACAKE_CONFIG_ALL_OUTPUT);
uint8_t reg = operacake_read_reg(oc_bus, addr, OPERACAKE_REG_CONFIG);
operacake_boards[addr].present = (reg == OPERACAKE_CONFIG_ALL_OUTPUT);
operacake_boards[addr].mode = MODE_MANUAL;
operacake_boards[addr].PA = OPERACAKE_PORT_A1;
operacake_boards[addr].PB = OPERACAKE_PORT_B1;
}
allow_gpio_mode = allow_gpio;
if (allow_gpio) {
operacake_sctimer_init();
}
return 0;
}
bool operacake_is_board_present(uint8_t address) {
if (address >= OPERACAKE_MAX_BOARDS)
return false;
return operacake_boards[address].present;
}
void operacake_get_boards(uint8_t *addresses) {
int count = 0;
for (int i = 0; i < OPERACAKE_MAX_BOARDS; i++) {
addresses[i] = OPERACAKE_ADDRESS_INVALID;
}
for (int i = 0; i < OPERACAKE_MAX_BOARDS; i++) {
if (operacake_is_board_present(i))
addresses[count++] = i;
}
}
uint8_t port_to_pins(uint8_t port) {
switch(port) {
case OPERACAKE_PA1:
return OPERACAKE_PORT_A1;
case OPERACAKE_PA2:
return OPERACAKE_PORT_A2;
case OPERACAKE_PA3:
return OPERACAKE_PORT_A3;
case OPERACAKE_PA4:
return OPERACAKE_PORT_A4;
case OPERACAKE_PB1:
return OPERACAKE_PORT_B1;
case OPERACAKE_PB2:
return OPERACAKE_PORT_B2;
case OPERACAKE_PB3:
return OPERACAKE_PORT_B3;
case OPERACAKE_PB4:
return OPERACAKE_PORT_B4;
}
return 0xFF;
}
/*
* Issue I2C command to activate ports.
*/
uint8_t operacake_activate_ports(uint8_t address, uint8_t PA, uint8_t PB)
{
uint8_t side, pa, pb, reg;
/* Ensure PA and PB are within the valid range. */
if ((PA > OPERACAKE_PB4) || (PB > OPERACAKE_PB4)) {
return 1;
}
/* Ensure PA and PB are on opposite sides. */
if (((PA <= OPERACAKE_PA4) && (PB <= OPERACAKE_PA4))
|| ((PA > OPERACAKE_PA4) && (PB > OPERACAKE_PA4))) {
return 1;
}
if (PA > OPERACAKE_PA4) {
side = OPERACAKE_CROSSOVER;
} else {
side = OPERACAKE_SAMESIDE;
}
pa = port_to_pins(PA);
pb = port_to_pins(PB);
reg = (OPERACAKE_GPIO_DISABLE | side | pa | pb | OPERACAKE_EN_LEDS);
operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, reg);
return 0;
}
void operacake_set_mode(uint8_t address, uint8_t mode) {
if (address >= OPERACAKE_MAX_BOARDS)
return;
operacake_boards[address].mode = mode;
current_range = INVALID_RANGE;
if (mode == MODE_TIME) {
// Switch Opera Cake to pin-control mode
uint8_t config_pins = (uint8_t)~(OPERACAKE_PIN_OE(1) | OPERACAKE_PIN_LEDEN(1) | OPERACAKE_PIN_LEDEN2(1));
operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG, config_pins);
operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, OPERACAKE_GPIO_ENABLE | OPERACAKE_EN_LEDS);
} else {
operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG, OPERACAKE_CONFIG_ALL_OUTPUT);
operacake_activate_ports(address, operacake_boards[address].PA, operacake_boards[address].PB);
}
// If any boards are in MODE_TIME, enable the sctimer events.
bool enable_sctimer = false;
for (int i = 0; i < OPERACAKE_MAX_BOARDS; i++) {
if (operacake_boards[i].mode == MODE_TIME)
enable_sctimer = true;
}
operacake_sctimer_enable(enable_sctimer);
}
uint8_t operacake_get_mode(uint8_t address) {
if (address >= OPERACAKE_MAX_BOARDS)
return 0;
return operacake_boards[address].mode;
}
/*
* Set manual mode ports.
*/
uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB)
{
/* Ensure PA and PB are within the valid range. */
if ((PA > OPERACAKE_PB4) || (PB > OPERACAKE_PB4)) {
return 1;
}
/* Ensure PA and PB are on opposite sides. */
if (((PA <= OPERACAKE_PA4) && (PB <= OPERACAKE_PA4))
|| ((PA > OPERACAKE_PA4) && (PB > OPERACAKE_PA4))) {
return 1;
}
// Keep track of manual settings for when we switch in/out of time/frequency modes.
operacake_boards[address].PA = PA;
operacake_boards[address].PB = PB;
// Immediately apply register settings if the board is in manual mode.
if (operacake_boards[address].mode == MODE_MANUAL) {
return operacake_activate_ports(address, PA, PB);
}
return 0;
}
/*
* frequency mode aka "Opera Glasses"
*/
typedef struct {
uint16_t freq_min;
uint16_t freq_max;
uint8_t portA;
uint8_t portB;
} operacake_range;
static operacake_range ranges[MAX_OPERACAKE_RANGES * sizeof(operacake_range)];
static uint8_t range_idx = 0;
uint8_t operacake_add_range(uint16_t freq_min, uint16_t freq_max, uint8_t port) {
if(range_idx >= MAX_OPERACAKE_RANGES) {
return 1;
}
ranges[range_idx].freq_min = freq_min;
ranges[range_idx].freq_max = freq_max;
ranges[range_idx].portA = port;
/* Make the B port mirror the A port. */
ranges[range_idx].portB = (port + 4) % 8;
range_idx++;
current_range = INVALID_RANGE;
return 0;
}
void operacake_clear_ranges(void)
{
range_idx = 0;
}
#define FREQ_ONE_MHZ (1000000ull)
uint8_t operacake_set_range(uint32_t freq_mhz) {
if(range_idx == 0) {
return 1;
}
int range;
for(range=0; range<range_idx; range++) {
if((freq_mhz >= ranges[range].freq_min)
&& (freq_mhz <= ranges[range].freq_max)) {
break;
}
}
/* Use the last range if there was no match. */
if (range == range_idx) {
range--;
}
if(range == current_range) {
return 1;
}
for (int i = 0; i < OPERACAKE_MAX_BOARDS; i++) {
if (operacake_is_board_present(i) && operacake_get_mode(i) == MODE_FREQUENCY) {
operacake_activate_ports(i, ranges[range].portA, ranges[range].portB);
break;
}
}
current_range = range;
return 0;
}
/*
* GPIO
*/
uint16_t gpio_test(uint8_t address)
{
uint8_t i, reg, bit_mask, gpio_mask = 0x1F;
uint16_t result = 0;
if(!allow_gpio_mode)
return 0xFFFF;
scu_pinmux(SCU_PINMUX_GPIO3_8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_GPIO3_12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_GPIO3_13, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_GPIO3_14, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_GPIO3_15, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
static struct gpio_t gpio_pins[] = {
GPIO(3, 8), // u1ctrl IO2
GPIO(3, 14), // u3ctrl0 IO3
GPIO(3, 15), // u3ctrl1 IO4
GPIO(3, 12), // u2ctrl0 IO5
GPIO(3, 13) // u2ctrl1 IO6
};
// Setup I2C to put it in GPIO mode
reg = (OPERACAKE_GPIO_ENABLE | OPERACAKE_EN_LEDS);
operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, reg);
operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG,
OPERACAKE_CONFIG_GPIO_INPUTS);
operacake_write_reg(oc_bus, address, OPERACAKE_REG_POLARITY,
OPERACAKE_POLARITY_NORMAL);
// clear state
for(i=0; i<5; i++) {
gpio_output(&gpio_pins[i]);
gpio_write(&gpio_pins[i], 0);
}
// Test each pin separately
for(i=0; i<5; i++) {
// Set pin high
gpio_write(&gpio_pins[i], 1);
// check input
reg = operacake_read_reg(oc_bus, address, OPERACAKE_REG_INPUT);
reg >>= 2;
reg &= gpio_mask;
bit_mask = 1 << i;
result <<= 1;
if(!(reg & bit_mask)) {
// Is the correct bit set?
result |= 1;
}
result <<= 1;
if(reg & ~bit_mask) {
// Are any other bits set?
result |= 1;
}
result <<= 1;
// set pin low
gpio_write(&gpio_pins[i], 0);
// check input
reg = operacake_read_reg(oc_bus, address, OPERACAKE_REG_INPUT);
reg >>= 2;
reg &= gpio_mask;
bit_mask = 1 << i;
if(reg & bit_mask) {
// Is the correct bit clear?
result |= 1;
}
}
// clean up
for(i=0; i<5; i++) {
gpio_input(&gpio_pins[i]);
}
// Put it back in to I2C mode and set default pins
operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG,
OPERACAKE_CONFIG_ALL_OUTPUT);
operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT,
OPERACAKE_DEFAULT_OUTPUT);
return result;
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2016 Dominic Spill <dominicgs@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.
*/
#ifndef __OPERACAKE_H
#define __OPERACAKE_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#include <stdbool.h>
#define OPERACAKE_PA1 0
#define OPERACAKE_PA2 1
#define OPERACAKE_PA3 2
#define OPERACAKE_PA4 3
#define OPERACAKE_PB1 4
#define OPERACAKE_PB2 5
#define OPERACAKE_PB3 6
#define OPERACAKE_PB4 7
#define MAX_OPERACAKE_RANGES 8
uint8_t operacake_init(bool allow_gpio);
bool operacake_is_board_present(uint8_t address);
void operacake_get_boards(uint8_t *addresses);
void operacake_set_mode(uint8_t address, uint8_t mode);
uint8_t operacake_get_mode(uint8_t address);
uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB);
uint8_t operacake_add_range(uint16_t freq_min, uint16_t freq_max, uint8_t port);
uint8_t operacake_set_range(uint32_t freq_mhz);
void operacake_clear_ranges(void);
uint16_t gpio_test(uint8_t address);
#ifdef __cplusplus
}
#endif
#endif /* __OPERACAKE_H */

View File

@ -0,0 +1,216 @@
/*
* Copyright 2018 Schuyler St. Leger
* Copyright 2021 Great Scott Gadgets
*
* 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 "operacake_sctimer.h"
#include <hackrf_core.h>
#include <libopencm3/lpc43xx/sgpio.h>
#include <libopencm3/lpc43xx/rgu.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/gima.h>
#include "sct.h"
#define U1CTRL_SET SCT_OUT14_SET
#define U1CTRL_CLR SCT_OUT14_CLR
#define U2CTRL0_SET SCT_OUT13_SET
#define U2CTRL0_CLR SCT_OUT13_CLR
#define U2CTRL1_SET SCT_OUT12_SET
#define U2CTRL1_CLR SCT_OUT12_CLR
#define U3CTRL0_SET SCT_OUT11_SET
#define U3CTRL0_CLR SCT_OUT11_CLR
#define U3CTRL1_SET SCT_OUT8_SET
#define U3CTRL1_CLR SCT_OUT8_CLR
static uint32_t default_output = 0;
/**
* Configure the SCTimer to rotate the antennas with the Operacake in phase with
* the sample clock. This will configure the SCTimer to output to the pins for
* GPIO control of the Operacake, however the Operacake must be configured for
* GPIO control. The timing is not set in this function.
*
* To trigger the antenna switching synchronously with the sample clock, the
* SGPIO is configured to output its clock (f=2 * sample clock) to the SCTimer.
*/
void operacake_sctimer_init() {
// We start by resetting the SCTimer
RESET_CTRL1 = RESET_CTRL1_SCT_RST;
// Delay to allow reset sigal to be processed
// The reset generator uses a 12MHz clock (IRC)
// The difference between this and the core clock (CCLK)
// determines this value (CCLK/IRC).
// The value used here is a bit shorter than would be required, since
// there are additional instructions that fill the time. If the duration of
// the actions from here to the first access to the SCTimer is changed, then
// this delay may need to be increased.
delay(8);
// Pin definitions for the HackRF
// U2CTRL0
scu_pinmux(P7_4, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
// U2CTRL1
scu_pinmux(P7_5, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
// U3CTRL0
scu_pinmux(P7_6, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
// U3CTRL1
scu_pinmux(P7_7, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
// U1CTRL
scu_pinmux(P7_0, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
// Configure the SGPIO to output the clock (f=2 * sample clock) on pin 12
SGPIO_OUT_MUX_CFG12 =
SGPIO_OUT_MUX_CFG_P_OUT_CFG(0x08) | // clkout output mode
SGPIO_OUT_MUX_CFG_P_OE_CFG(0); // gpio_oe
SGPIO_GPIO_OENREG |= BIT12;
// Use the GIMA to connect the SGPIO clock to the SCTimer
GIMA_CTIN_1_IN = 0x2 << 4; // Route SGPIO12 to SCTIN1
// We configure this register first, because the user manual says to
SCT_CONFIG |= SCT_CONFIG_UNIFY_32_BIT
| SCT_CONFIG_CLKMODE_PRESCALED_BUS_CLOCK
| SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_1;
// Halt the SCTimer to enable it to be configured
SCT_CTRL = SCT_CTRL_HALT_L(1);
// Prescaler - run at half the SGPIO clock (ie: at the sample clock)
SCT_CTRL |= SCT_CTRL_PRE_L(1);
// Default to state 0, events disabled
SCT_STATE = 0;
// Enable the SCTimer
SCT_CTRL &= ~SCT_CTRL_HALT_L(1);
}
static uint32_t operacake_sctimer_port_to_output(uint8_t port) {
int bit0 = (port >> 0) & 1;
int bit1 = (port >> 1) & 1;
int bit2 = (port >> 2) & 1;
return (bit0 << 11) | (bit0 << 13) |
(bit1 << 8) | (bit1 << 12) |
(((~bit2)&1) << 14);
}
void operacake_sctimer_enable(bool enable) {
SCT_CTRL = SCT_CTRL_HALT_L(1);
SCT_STATE = enable;
SCT_CTRL &= ~SCT_CTRL_HALT_L(1);
}
void operacake_sctimer_set_dwell_times(struct operacake_dwell_times *times, int n) {
SCT_CTRL = SCT_CTRL_HALT_L(1);
uint32_t counter = 0;
uint32_t bit0_set = 0, bit0_clr = 0, bit1_set = 0, bit1_clr = 0, bit2_set = 0, bit2_clr = 0;
for (int i = 0; i < n; i++) {
// Enable event i in state 1, set to match on match register i
SCT_EVn_STATE(i) = SCT_EVn_STATE_STATEMSK1(1);
SCT_EVn_CTRL(i) = SCT_EVn_CTRL_COMBMODE_MATCH | SCT_EVn_CTRL_MATCHSEL(i);
// Calculate the counter value to match on
counter += times[i].dwell;
// Wrapping from SCT_LIMIT seems to add an extra cycle,
// so we reduce the counter value for the first event.
if (i == 0)
counter -= 1;
SCT_MATCHn(i) = counter;
SCT_MATCHRELn(i) = counter;
// The match event selects the *next* port, so retreive that here.
int port;
if (i == n - 1) {
port = times[0].port;
} else {
port = times[i+1].port;
}
int bit0 = (port >> 0) & 1;
int bit1 = (port >> 1) & 1;
int bit2 = (port >> 2) & 1;
// Find bits to set/clear on event i
bit0_set |= SCT_OUTn_SETm( bit0, i);
bit0_clr |= SCT_OUTn_CLRm(~bit0, i);
bit1_set |= SCT_OUTn_SETm( bit1, i);
bit1_clr |= SCT_OUTn_CLRm(~bit1, i);
// (U1CTRL is inverted)
bit2_set |= SCT_OUTn_SETm(~bit2, i);
bit2_clr |= SCT_OUTn_CLRm( bit2, i);
}
// Apply event set/clear mappings
U2CTRL0_SET = bit0_set;
U2CTRL0_CLR = bit0_clr;
U3CTRL0_SET = bit0_set;
U3CTRL0_CLR = bit0_clr;
U2CTRL1_SET = bit1_set;
U2CTRL1_CLR = bit1_clr;
U3CTRL1_SET = bit1_set;
U3CTRL1_CLR = bit1_clr;
U1CTRL_SET = bit2_set;
U1CTRL_CLR = bit2_clr;
// Set output pins to select the first port in the list
default_output = operacake_sctimer_port_to_output(times[0].port);
SCT_OUTPUT = default_output;
// Reset counter on final event
SCT_LIMIT = (1 << (n-1));
SCT_CTRL &= ~SCT_CTRL_HALT_L(1);
}
void operacake_sctimer_stop() {
// Halt timer
SCT_CTRL |= SCT_CTRL_HALT_L(1);
}
/**
* This will reset the state of the SCTimer, but retains its configuration.
* This reset will return the selected antenna to 1 and samesided. This is
* called by set_transceiver_mode so the HackRF starts capturing with the
* same antenna selected each time.
*/
void operacake_sctimer_reset_state() {
SCT_CTRL |= SCT_CTRL_HALT_L(1);
// Clear the counter value
SCT_CTRL |= SCT_CTRL_CLRCTR_L(1);
// Reset to select the first port
SCT_OUTPUT = default_output;
SCT_CTRL &= ~SCT_CTRL_HALT_L(1);
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2016 Dominic Spill <dominicgs@gmail.com>
* Copyright 2018 Schuyler St. Leger
* Copyright 2021 Great Scott Gadgets
*
* 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 __OPERACAKE_SCTIMER_H
#define __OPERACAKE_SCTIMER_H
#include <stdbool.h>
#include <stdint.h>
struct operacake_dwell_times {
uint32_t dwell;
uint8_t port;
};
void operacake_sctimer_init();
void operacake_sctimer_enable(bool enable);
void operacake_sctimer_set_dwell_times(struct operacake_dwell_times *times, int n);
void operacake_sctimer_stop();
void operacake_sctimer_reset_state();
#endif /* __OPERACAKE_SCTIMER_H */

View File

@ -0,0 +1,577 @@
/*
* Copyright 2018 Jared Boone
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "portapack.h"
#include "hackrf_core.h"
#include "gpio_lpc.h"
#include <libopencm3/lpc43xx/scu.h>
static void portapack_sleep_milliseconds(const uint32_t milliseconds) {
/* NOTE: Naively assumes 204 MHz instruction cycle clock and five instructions per count */
delay(milliseconds * 40800);
}
static struct gpio_t gpio_io_stbx = GPIO(5, 0); /* P2_0 */
static struct gpio_t gpio_addr = GPIO(5, 1); /* P2_1 */
__attribute__((unused)) static struct gpio_t gpio_lcd_te = GPIO(5, 3); /* P2_3 */
__attribute__((unused)) static struct gpio_t gpio_unused = GPIO(5, 7); /* P2_8 */
static struct gpio_t gpio_lcd_rdx = GPIO(5, 4); /* P2_4 */
static struct gpio_t gpio_lcd_wrx = GPIO(1, 10); /* P2_9 */
static struct gpio_t gpio_dir = GPIO(1, 13); /* P2_13 */
typedef struct portapack_if_t {
gpio_t gpio_dir;
gpio_t gpio_lcd_rdx;
gpio_t gpio_lcd_wrx;
gpio_t gpio_io_stbx;
gpio_t gpio_addr;
gpio_port_t* const gpio_port_data;
uint8_t io_reg;
} portapack_if_t;
static portapack_if_t portapack_if = {
.gpio_dir = &gpio_dir,
.gpio_lcd_rdx = &gpio_lcd_rdx,
.gpio_lcd_wrx = &gpio_lcd_wrx,
.gpio_io_stbx = &gpio_io_stbx,
.gpio_addr = &gpio_addr,
.gpio_port_data = GPIO_LPC_PORT(3),
.io_reg = 0x03,
};
/* NOTE: Code below assumes the shift value is "8". */
#define GPIO_DATA_SHIFT (8)
static const uint32_t gpio_data_mask = 0xFFU << GPIO_DATA_SHIFT;
static void portapack_data_mask_set() {
portapack_if.gpio_port_data->mask = ~gpio_data_mask;
}
static void portapack_data_write_low(const uint32_t value) {
portapack_if.gpio_port_data->mpin = (value << GPIO_DATA_SHIFT);
}
static void portapack_data_write_high(const uint32_t value) {
/* NOTE: Assumes no other bits in the port are masked. */
/* NOTE: Assumes that bits 15 through 8 are masked. */
portapack_if.gpio_port_data->mpin = value;
}
static void portapack_dir_read() {
portapack_if.gpio_port_data->dir &= ~gpio_data_mask;
gpio_set(portapack_if.gpio_dir);
}
static void portapack_dir_write() {
gpio_clear(portapack_if.gpio_dir);
portapack_if.gpio_port_data->dir |= gpio_data_mask;
/* TODO: Manipulating DIR[3] makes me queasy. The RFFC5072 DATA pin
* is also on port 3, and switches direction periodically...
* Time to resort to bit-banding to enforce atomicity? But then, how
* to change direction on eight bits efficiently? Or do I care, since
* the PortaPack data bus shouldn't change direction too frequently?
*/
}
__attribute__((unused)) static void portapack_lcd_rd_assert() {
gpio_clear(portapack_if.gpio_lcd_rdx);
}
static void portapack_lcd_rd_deassert() {
gpio_set(portapack_if.gpio_lcd_rdx);
}
static void portapack_lcd_wr_assert() {
gpio_clear(portapack_if.gpio_lcd_wrx);
}
static void portapack_lcd_wr_deassert() {
gpio_set(portapack_if.gpio_lcd_wrx);
}
static void portapack_io_stb_assert() {
gpio_clear(portapack_if.gpio_io_stbx);
}
static void portapack_io_stb_deassert() {
gpio_set(portapack_if.gpio_io_stbx);
}
static void portapack_addr(const bool value) {
gpio_write(portapack_if.gpio_addr, value);
}
static void portapack_lcd_command(const uint32_t value) {
portapack_data_write_high(0); /* Drive high byte (with zero -- don't care) */
portapack_dir_write(); /* Turn around data bus, MCU->CPLD */
portapack_addr(0); /* Indicate command */
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_lcd_wr_assert(); /* Latch high byte */
portapack_data_write_low(value); /* Drive low byte (pass-through) */
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_lcd_wr_deassert(); /* Complete write operation */
portapack_addr(1); /* Set up for data phase (most likely after a command) */
}
static void portapack_lcd_write_data(const uint32_t value) {
// NOTE: Assumes and DIR=0 and ADDR=1 from command phase.
portapack_data_write_high(value); /* Drive high byte */
__asm__("nop");
portapack_lcd_wr_assert(); /* Latch high byte */
portapack_data_write_low(value); /* Drive low byte (pass-through) */
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_lcd_wr_deassert(); /* Complete write operation */
}
static void portapack_io_write(const bool address, const uint_fast16_t value) {
portapack_data_write_low(value);
portapack_dir_write();
portapack_addr(address);
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_io_stb_assert();
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_io_stb_deassert();
}
static void portapack_if_init() {
portapack_data_mask_set();
portapack_data_write_high(0);
portapack_dir_read();
portapack_lcd_rd_deassert();
portapack_lcd_wr_deassert();
portapack_io_stb_deassert();
portapack_addr(0);
gpio_output(portapack_if.gpio_dir);
gpio_output(portapack_if.gpio_lcd_rdx);
gpio_output(portapack_if.gpio_lcd_wrx);
gpio_output(portapack_if.gpio_io_stbx);
gpio_output(portapack_if.gpio_addr);
/* gpio_input(portapack_if.gpio_rot_a); */
/* gpio_input(portapack_if.gpio_rot_b); */
scu_pinmux(SCU_PINMUX_PP_D0, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D1, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D2, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D3, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D4, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D5, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D6, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D7, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_DIR, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_PP_LCD_RDX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_PP_LCD_WRX, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_PP_IO_STBX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_PP_ADDR, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL);
/* scu_pinmux(SCU_PINMUX_PP_LCD_TE, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */
/* scu_pinmux(SCU_PINMUX_PP_UNUSED, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */
}
static void portapack_lcd_reset_state(const bool active) {
portapack_if.io_reg = (portapack_if.io_reg & 0xfe) | (active ? (1 << 0) : 0);
portapack_io_write(1, portapack_if.io_reg);
}
static void portapack_lcd_data_write_command_and_data(
const uint_fast8_t command,
const uint8_t* data,
const size_t data_count
) {
portapack_lcd_command(command);
for(size_t i=0; i<data_count; i++) {
portapack_lcd_write_data(data[i]);
}
}
static void portapack_lcd_sleep_out() {
const uint8_t cmd_11[] = {};
portapack_lcd_data_write_command_and_data(0x11, cmd_11, ARRAY_SIZEOF(cmd_11));
// "It will be necessary to wait 120msec after sending Sleep Out
// command (when in Sleep In Mode) before Sleep In command can be
// sent."
portapack_sleep_milliseconds(120);
}
static void portapack_lcd_display_on() {
const uint8_t cmd_29[] = {};
portapack_lcd_data_write_command_and_data(0x29, cmd_29, ARRAY_SIZEOF(cmd_29));
}
static void portapack_lcd_ramwr_start() {
const uint8_t cmd_2c[] = {};
portapack_lcd_data_write_command_and_data(0x2c, cmd_2c, ARRAY_SIZEOF(cmd_2c));
}
static void portapack_lcd_set(const uint_fast8_t command, const uint_fast16_t start, const uint_fast16_t end) {
const uint8_t data[] = {
(start >> 8), (start & 0xff),
(end >> 8), (end & 0xff)
};
portapack_lcd_data_write_command_and_data(command, data, ARRAY_SIZEOF(data));
}
static void portapack_lcd_caset(const uint_fast16_t start_column, const uint_fast16_t end_column) {
portapack_lcd_set(0x2a, start_column, end_column);
}
static void portapack_lcd_paset(const uint_fast16_t start_page, const uint_fast16_t end_page) {
portapack_lcd_set(0x2b, start_page, end_page);
}
static void portapack_lcd_start_ram_write(
const ui_rect_t rect
) {
portapack_lcd_caset(rect.point.x, rect.point.x + rect.size.width - 1);
portapack_lcd_paset(rect.point.y, rect.point.y + rect.size.height - 1);
portapack_lcd_ramwr_start();
}
static void portapack_lcd_write_pixel(const ui_color_t pixel) {
portapack_lcd_write_data(pixel.v);
}
static void portapack_lcd_write_pixels_color(const ui_color_t c, size_t n) {
while(n--) {
portapack_lcd_write_data(c.v);
}
}
static void portapack_lcd_wake() {
portapack_lcd_sleep_out();
portapack_lcd_display_on();
}
static void portapack_lcd_reset() {
portapack_lcd_reset_state(false);
portapack_sleep_milliseconds(1);
portapack_lcd_reset_state(true);
portapack_sleep_milliseconds(10);
portapack_lcd_reset_state(false);
portapack_sleep_milliseconds(120);
}
static void portapack_lcd_init() {
// LCDs are configured for IM[2:0] = 001
// 8080-I system, 16-bit parallel bus
//
// 0x3a: DBI[2:0] = 101
// MDT[1:0] = XX (if not in 18-bit mode, right?)
// Power control B
// 0
// PCEQ=1, DRV_ena=0, Power control=3
const uint8_t cmd_cf[] = { 0x00, 0xD9, 0x30 };
portapack_lcd_data_write_command_and_data(0xCF, cmd_cf, ARRAY_SIZEOF(cmd_cf));
// Power on sequence control
const uint8_t cmd_ed[] = { 0x64, 0x03, 0x12, 0x81 };
portapack_lcd_data_write_command_and_data(0xED, cmd_ed, ARRAY_SIZEOF(cmd_ed));
// Driver timing control A
const uint8_t cmd_e8[] = { 0x85, 0x10, 0x78 };
portapack_lcd_data_write_command_and_data(0xE8, cmd_e8, ARRAY_SIZEOF(cmd_e8));
// Power control A
const uint8_t cmd_cb[] = { 0x39, 0x2C, 0x00, 0x34, 0x02 };
portapack_lcd_data_write_command_and_data(0xCB, cmd_cb, ARRAY_SIZEOF(cmd_cb));
// Pump ratio control
const uint8_t cmd_f7[] = { 0x20 };
portapack_lcd_data_write_command_and_data(0xF7, cmd_f7, ARRAY_SIZEOF(cmd_f7));
// Driver timing control B
const uint8_t cmd_ea[] = { 0x00, 0x00 };
portapack_lcd_data_write_command_and_data(0xEA, cmd_ea, ARRAY_SIZEOF(cmd_ea));
const uint8_t cmd_b1[] = { 0x00, 0x1B };
portapack_lcd_data_write_command_and_data(0xB1, cmd_b1, ARRAY_SIZEOF(cmd_b1));
// Blanking Porch Control
// VFP = 0b0000010 = 2 (number of HSYNC of vertical front porch)
// VBP = 0b0000010 = 2 (number of HSYNC of vertical back porch)
// HFP = 0b0001010 = 10 (number of DOTCLOCK of horizontal front porch)
// HBP = 0b0010100 = 20 (number of DOTCLOCK of horizontal back porch)
const uint8_t cmd_b5[] = { 0x02, 0x02, 0x0a, 0x14 };
portapack_lcd_data_write_command_and_data(0xB5, cmd_b5, ARRAY_SIZEOF(cmd_b5));
// Display Function Control
// PT[1:0] = 0b10
// PTG[1:0] = 0b10
// ISC[3:0] = 0b0010 (scan cycle interval of gate driver: 5 frames)
// SM = 0 (gate driver pin arrangement in combination with GS)
// SS = 1 (source output scan direction S720 -> S1)
// GS = 0 (gate output scan direction G1 -> G320)
// REV = 1 (normally white)
// NL = 0b100111 (default)
// PCDIV = 0b000000 (default?)
const uint8_t cmd_b6[] = { 0x0A, 0xA2, 0x27, 0x00 };
portapack_lcd_data_write_command_and_data(0xB6, cmd_b6, ARRAY_SIZEOF(cmd_b6));
// Power Control 1
//VRH[5:0]
const uint8_t cmd_c0[] = { 0x1B };
portapack_lcd_data_write_command_and_data(0xC0, cmd_c0, ARRAY_SIZEOF(cmd_c0));
// Power Control 2
//SAP[2:0];BT[3:0]
const uint8_t cmd_c1[] = { 0x12 };
portapack_lcd_data_write_command_and_data(0xC1, cmd_c1, ARRAY_SIZEOF(cmd_c1));
// VCOM Control 1
const uint8_t cmd_c5[] = { 0x32, 0x3C };
portapack_lcd_data_write_command_and_data(0xC5, cmd_c5, ARRAY_SIZEOF(cmd_c5));
// VCOM Control 2
const uint8_t cmd_c7[] = { 0x9B };
portapack_lcd_data_write_command_and_data(0xC7, cmd_c7, ARRAY_SIZEOF(cmd_c7));
// Memory Access Control
// Invert X and Y memory access order, so upper-left of
// screen is (0,0) when writing to display.
const uint8_t cmd_36[] = {
(1 << 7) | // MY=1
(1 << 6) | // MX=1
(0 << 5) | // MV=0
(1 << 4) | // ML=1: reverse vertical refresh to simplify scrolling logic
(1 << 3) // BGR=1: For Kingtech LCD, BGR filter.
};
portapack_lcd_data_write_command_and_data(0x36, cmd_36, ARRAY_SIZEOF(cmd_36));
// COLMOD: Pixel Format Set
// DPI=101 (16 bits/pixel), DBI=101 (16 bits/pixel)
const uint8_t cmd_3a[] = { 0x55 };
portapack_lcd_data_write_command_and_data(0x3A, cmd_3a, ARRAY_SIZEOF(cmd_3a));
//portapack_lcd_data_write_command_and_data(0xF6, { 0x01, 0x30 });
// WEMODE=1 (reset column and page number on overflow)
// MDT[1:0]
// EPF[1:0]=00 (use channel MSB for LSB)
// RIM=0 (If COLMOD[6:4]=101 (65k color), 16-bit RGB interface (1 transfer/pixel))
// RM=0 (system interface/VSYNC interface)
// DM[1:0]=00 (internal clock operation)
// ENDIAN=0 (doesn't matter with 16-bit interface)
const uint8_t cmd_f6[] = { 0x01, 0x30, 0x00 };
portapack_lcd_data_write_command_and_data(0xF6, cmd_f6, ARRAY_SIZEOF(cmd_f6));
// 3Gamma Function Disable
const uint8_t cmd_f2[] = { 0x00 };
portapack_lcd_data_write_command_and_data(0xF2, cmd_f2, ARRAY_SIZEOF(cmd_f2));
// Gamma curve selected
const uint8_t cmd_26[] = { 0x01 };
portapack_lcd_data_write_command_and_data(0x26, cmd_26, ARRAY_SIZEOF(cmd_26));
// Set Gamma
const uint8_t cmd_e0[] = {
0x0F, 0x1D, 0x19, 0x0E, 0x10, 0x07, 0x4C, 0x63,
0x3F, 0x03, 0x0D, 0x00, 0x26, 0x24, 0x04
};
portapack_lcd_data_write_command_and_data(0xE0, cmd_e0, ARRAY_SIZEOF(cmd_e0));
// Set Gamma
const uint8_t cmd_e1[] = {
0x00, 0x1C, 0x1F, 0x02, 0x0F, 0x03, 0x35, 0x25,
0x47, 0x04, 0x0C, 0x0B, 0x29, 0x2F, 0x05
};
portapack_lcd_data_write_command_and_data(0xE1, cmd_e1, ARRAY_SIZEOF(cmd_e1));
portapack_lcd_wake();
// Turn on Tearing Effect Line (TE) output signal.
const uint8_t cmd_35[] = { 0b00000000 };
portapack_lcd_data_write_command_and_data(0x35, cmd_35, ARRAY_SIZEOF(cmd_35));
}
void portapack_backlight(const bool on) {
portapack_if.io_reg = (portapack_if.io_reg & 0x7f) | (on ? (1 << 7) : 0);
portapack_io_write(1, portapack_if.io_reg);
}
void portapack_reference_oscillator(const bool on) {
const uint8_t mask = 1 << 6;
portapack_if.io_reg = (portapack_if.io_reg & ~mask) | (on ? mask : 0);
portapack_io_write(1, portapack_if.io_reg);
}
void portapack_fill_rectangle(
const ui_rect_t rect,
const ui_color_t color
) {
portapack_lcd_start_ram_write(rect);
portapack_lcd_write_pixels_color(color, rect.size.width * rect.size.height);
}
void portapack_clear_display(const ui_color_t color) {
const ui_rect_t rect_screen = { { 0, 0 }, { 240, 320 } };
portapack_fill_rectangle(rect_screen, color);
}
void portapack_draw_bitmap(
const ui_point_t point,
const ui_bitmap_t bitmap,
const ui_color_t foreground,
const ui_color_t background
) {
const ui_rect_t rect = {
.point = point,
.size = bitmap.size
};
portapack_lcd_start_ram_write(rect);
const size_t count = bitmap.size.width * bitmap.size.height;
for(size_t i=0; i<count; i++) {
const uint8_t pixel = bitmap.data[i >> 3] & (1U << (i & 0x7));
portapack_lcd_write_pixel(pixel ? foreground : background);
}
}
ui_bitmap_t portapack_font_glyph(
const ui_font_t* const font,
const char c
) {
if( c >= font->c_start ) {
const uint_fast8_t index = c - font->c_start;
if( index < font->c_count ) {
const ui_bitmap_t bitmap = {
.size = font->glyph_size,
.data = &font->data[index * font->data_stride]
};
return bitmap;
}
}
const ui_bitmap_t bitmap = {
.size = font->glyph_size,
.data = font->data,
};
return bitmap;
}
static bool jtag_pp_tck(const bool tms_value) {
gpio_write(jtag_cpld.gpio->gpio_pp_tms, tms_value);
// 8 ns TMS/TDI to TCK setup
__asm__("nop");
__asm__("nop");
__asm__("nop");
gpio_set(jtag_cpld.gpio->gpio_tck);
// 15 ns TCK to TMS/TDI hold time
// 20 ns TCK high time
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
gpio_clear(jtag_cpld.gpio->gpio_tck);
// 20 ns TCK low time
// 25 ns TCK falling edge to TDO valid
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
return gpio_read(jtag_cpld.gpio->gpio_pp_tdo);
}
static uint32_t jtag_pp_shift(const uint32_t tms_bits, const size_t count) {
uint32_t result = 0;
size_t bit_in_index = count - 1;
size_t bit_out_index = 0;
while(bit_out_index < count) {
const uint32_t tdo = jtag_pp_tck((tms_bits >> bit_in_index) & 1) & 1;
result |= (tdo << bit_out_index);
bit_in_index--;
bit_out_index++;
}
return result;
}
static uint32_t jtag_pp_idcode(void) {
cpld_jtag_take(&jtag_cpld);
/* TODO: Check if PortaPack TMS is floating or driven by an external device. */
gpio_output(jtag_cpld.gpio->gpio_pp_tms);
/* Test-Logic/Reset -> Run-Test/Idle -> Select-DR/Scan -> Capture-DR */
jtag_pp_shift(0b11111010, 8);
/* Shift-DR */
const uint32_t idcode = jtag_pp_shift(0, 32);
/* Exit1-DR -> Update-DR -> Run-Test/Idle -> ... -> Test-Logic/Reset */
jtag_pp_shift(0b11011111, 8);
cpld_jtag_release(&jtag_cpld);
return idcode;
}
static bool portapack_detect(void) {
return jtag_pp_idcode() == 0x020A50DD;
}
static const portapack_t portapack_instance = {
};
static const portapack_t* portapack_pointer = NULL;
const portapack_t* portapack(void) {
return portapack_pointer;
}
void portapack_init(void) {
if( portapack_detect() ) {
portapack_if_init();
portapack_lcd_reset();
portapack_lcd_init();
portapack_pointer = &portapack_instance;
} else {
portapack_pointer = NULL;
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 2018 Jared Boone
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PORTAPACK_H__
#define __PORTAPACK_H__
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#define ARRAY_SIZEOF(x) (sizeof(x) / sizeof(x[0]))
typedef struct ui_color_t {
uint16_t v;
} ui_color_t;
typedef struct ui_point_t {
int16_t x;
int16_t y;
} ui_point_t;
typedef struct ui_size_t {
int16_t width;
int16_t height;
} ui_size_t;
typedef struct ui_rect_t {
ui_point_t point;
ui_size_t size;
} ui_rect_t;
typedef struct ui_bitmap_t {
ui_size_t size;
const uint8_t* const data;
} ui_bitmap_t;
typedef struct ui_font_t {
const ui_size_t glyph_size;
const uint8_t* const data;
char c_start;
size_t c_count;
size_t data_stride;
} ui_font_t;
typedef struct portapack_t {
} portapack_t;
void portapack_init(void);
/* If the "portapack" symbol is defined, PortaPack support is compiled in */
/* If the portapack() call returns non-NULL, a PortaPack was detected and is initialized. */
const portapack_t* portapack(void) __attribute__((weak));
void portapack_backlight(const bool on);
void portapack_reference_oscillator(const bool on) __attribute__((weak));
void portapack_fill_rectangle(
const ui_rect_t rect,
const ui_color_t color
);
void portapack_clear_display(const ui_color_t color);
void portapack_draw_bitmap(
const ui_point_t point,
const ui_bitmap_t bitmap,
const ui_color_t foreground,
const ui_color_t background
);
ui_bitmap_t portapack_font_glyph(
const ui_font_t* const font,
const char c
);
#endif/*__PORTAPACK_H__*/

View File

@ -0,0 +1,127 @@
#include "fonts.h"
#include "render.h"
#include <stdint.h>
// Local function: Get next nibble.
static int ctr = 0; // offset for next nibble
static int hilo = 0; // 0= high nibble next, 1=low nibble next
static const uint8_t *data;
#define MAXCHR (30 * 20)
static uint8_t charBuf[MAXCHR];
// Get next nibble
static uint8_t gnn()
{
static uint8_t byte;
uint8_t val;
if (hilo == 1)
ctr++;
hilo = 1 - hilo;
if (hilo == 1) {
byte = data[ctr];
val = byte >> 4;
} else {
val = byte & 0x0f;
};
return val;
}
// Local function: Unpack "long run".
static int upl(int off)
{
int retval;
while ((retval = gnn()) == 0) {
off++;
};
while (off-- > 0) {
retval = retval << 4;
retval += gnn();
};
return retval;
}
uint8_t *rad1o_pk_decode(const uint8_t *ldata, int *len)
{
ctr = 0;
hilo = 0;
data = ldata;
int length = *len; // Length of character bytestream
int height; // Height of character in bytes
int hoff; // bit position for non-integer heights
uint8_t *bufptr = charBuf; // Output buffer for decoded character
height = (rad1o_getFontHeight() - 1) / 8 + 1;
hoff = rad1o_getFontHeight() % 8;
#define DYN (12) // Decoder parameter: Fixed value for now.
int repeat = 0; // Decoder internal: repeat colum?
int curbit = 0; // Decoder internal: current bit (1 or 0)
int pos = 0; // Decoder internal: current bit position (0..7)
int nyb; // Decoder internal: current nibble / value
if (data[ctr] >> 4 == 14) { // Char starts with 1-bits.
gnn();
curbit = 1;
};
while (ctr < length) { /* Iterate the whole input stream */
/* Get next encoded nibble and decode */
nyb = gnn();
if (nyb == 15) {
repeat++;
continue;
} else if (nyb == 14) {
nyb = upl(0);
nyb += 1;
repeat += nyb;
continue;
} else if (nyb > DYN) {
nyb = (16 * (nyb - DYN - 1)) + gnn() + DYN + 1;
} else if (nyb == 0) {
nyb = upl(1);
nyb += (16 * (13 - DYN) + DYN) - 16;
};
/* Generate & output bits */
while (nyb-- > 0) {
if (pos == 0) // Clear each byte before we start.
*bufptr = 0;
if (curbit == 1) {
*bufptr |= 1 << (7 - pos);
};
pos++;
if (((bufptr - charBuf) % height) == (height - 1) &&
(pos == hoff)) {
// Finish incomplete last byte per column
pos = 8;
};
if (pos == 8) {
bufptr++;
if ((bufptr - charBuf) % height ==
0) { // End of column?
while (repeat > 0) {
for (int y = 0; y < height;
y++) {
bufptr[0] =
bufptr[-height];
bufptr++;
};
repeat--;
};
};
pos = 0;
};
};
curbit = 1 - curbit;
};
*len = (bufptr - charBuf) / height; // return size of output buffer.
return charBuf;
}

View File

@ -0,0 +1,8 @@
#ifndef __RAD1O_DECODER_H__
#define __RAD1O_DECODER_H__
#include <stdint.h>
uint8_t *rad1o_pk_decode(const uint8_t *data, int *len);
#endif

View File

@ -0,0 +1,180 @@
#include "display.h"
#include "gpio_lpc.h"
#include "hackrf_core.h"
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/ssp.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
static void delayms(const uint32_t milliseconds)
{
/* NOTE: Naively assumes 204 MHz instruction cycle clock and five instructions per count */
delay(milliseconds * 40800);
}
static struct gpio_t gpio_lcd_cs = GPIO(4, 12); /* P9_0 */
static struct gpio_t gpio_lcd_bl_en = GPIO(0, 8); /* P1_1 */
static struct gpio_t gpio_lcd_reset = GPIO(5, 17); /* P9_4 */
/**************************************************************************/
/* Utility routines to manage nokia display */
/**************************************************************************/
static void rotate(void);
static uint8_t lcdBuffer[RESX * RESY];
static bool isTurned;
static void select()
{
/*
* The LCD requires 9-Bit frames
* Freq = PCLK / (CPSDVSR * [SCR+1])
* We want 120ns / bit -> 8.3 MHz.
* SPI1 BASE CLOCK is expected to be 204 MHz.
* 204 MHz / ( 12 * (1 + 1)) = 8.5 MHz
*
* Set CPSDVSR = 12
*/
uint8_t serial_clock_rate = 1;
uint8_t clock_prescale_rate = 12;
ssp_init(LCD_SSP, SSP_DATA_9BITS, SSP_FRAME_SPI, SSP_CPOL_0_CPHA_0,
serial_clock_rate, clock_prescale_rate, SSP_MODE_NORMAL,
SSP_MASTER, SSP_SLAVE_OUT_ENABLE);
gpio_clear(&gpio_lcd_cs);
}
static void deselect()
{
gpio_set(&gpio_lcd_cs);
}
static void write(uint8_t cd, uint8_t data)
{
uint16_t frame = 0x0;
frame = cd << 8;
frame |= data;
ssp_transfer(LCD_SSP, frame);
}
void rad1o_lcdInit(void)
{
gpio_output(&gpio_lcd_bl_en);
gpio_output(&gpio_lcd_reset);
gpio_output(&gpio_lcd_cs);
/* prepare SPI */
SETUPpin(LCD_DI);
SETUPpin(LCD_SCK);
// Reset the display
gpio_clear(&gpio_lcd_reset);
delayms(100);
gpio_set(&gpio_lcd_reset);
delayms(100);
select();
/* The controller is a PCF8833 - documentation can be found online. */
static uint8_t initseq_d[] = {
0x11, // SLEEP_OUT (wake up)
0x3A, 2, // mode 8bpp (2= 8bpp, 3= 12bpp, 5= 16bpp)
0x36, 0b11000000, // my,mx,v,lao,rgb,x,x,x
0x25, 0x3a, // set contrast
0x29, // display on
0x03, // BSTRON (booster voltage)
0x2A, 1, RESX, 0x2B, 1, RESY
};
uint16_t initseq_c = ~(/* commands: 1, data: 0 */
(1 << 0) | (1 << 1) | (0 << 2) | (1 << 3) |
(0 << 4) | (1 << 5) | (0 << 6) | (1 << 7) |
(1 << 8) | (1 << 9) | (0 << 10) | (0 << 11) |
(1 << 12) | (0 << 13) | (0 << 14) | 0);
write(0, 0x01); /* most color displays need the pause */
delayms(10);
size_t i = 0;
while (i < sizeof(initseq_d)) {
write(initseq_c & 1, initseq_d[i++]);
initseq_c = initseq_c >> 1;
}
deselect();
rad1o_lcdFill(0xff); /* Clear display buffer */
rotate();
gpio_set(&gpio_lcd_bl_en);
}
void rad1o_lcdDeInit(void)
{
gpio_clear(&gpio_lcd_bl_en);
rad1o_lcdFill(0xff);
rad1o_lcdDisplay();
}
void rad1o_lcdFill(uint8_t f)
{
memset(lcdBuffer, f, RESX * RESY);
}
void rad1o_lcdSetPixel(uint8_t x, uint8_t y, uint8_t f)
{
if (x > RESX || y > RESY)
return;
lcdBuffer[y * RESX + x] = f;
}
static uint8_t getPixel(uint8_t x, uint8_t y)
{
return lcdBuffer[y * RESX + x];
}
uint8_t *rad1o_lcdGetBuffer(void)
{
return lcdBuffer;
}
void rad1o_lcdDisplay(void)
{
select();
uint16_t x, y;
/* set (back) to 8 bpp mode */
write(TYPE_CMD, 0x3a);
write(TYPE_DATA, 2);
write(TYPE_CMD, 0x2C); // memory write (RAMWR)
for (y = 0; y < RESY; y++) {
for (x = 0; x < RESX; x++) {
write(TYPE_DATA, getPixel(x, y));
};
}
deselect();
}
static void rotate(void)
{
select();
write(TYPE_CMD, 0x36); // MDAC-Command
if (isTurned) {
write(TYPE_DATA, 0b01100000); // my,mx,v,lao,rgb,x,x,x
isTurned = true;
} else {
write(TYPE_DATA, 0b11000000); // my,mx,v,lao,rgb,x,x,x
isTurned = false;
}
deselect();
rad1o_lcdDisplay();
}

View File

@ -0,0 +1,30 @@
#ifndef __RAD1O_DISPLAY_H__
#define __RAD1O_DISPLAY_H__
#include <libopencm3/cm3/common.h>
#include <stdint.h>
#define RESX 130
#define RESY 130
#define TYPE_CMD 0
#define TYPE_DATA 1
#define _PIN(pin, func, ...) pin
#define _FUNC(pin, func, ...) func
#define SETUPpin(args...) scu_pinmux(_PIN(args), _FUNC(args))
#define LCD_DI P1_4, SCU_CONF_FUNCTION5 | SCU_SSP_IO
#define LCD_SCK P1_19, SCU_CONF_FUNCTION1 | SCU_SSP_IO
#define LCD_SSP SSP1_NUM
void rad1o_lcdInit(void);
void rad1o_lcdDeInit(void);
void rad1o_lcdFill(uint8_t f);
void rad1o_lcdDisplay(void);
void rad1o_lcdSetPixel(uint8_t x, uint8_t y, uint8_t f);
uint8_t *rad1o_lcdGetBuffer(void);
#endif

View File

@ -0,0 +1,30 @@
#include "display.h"
#include <stdint.h>
#define SWAP(p1, p2) \
do { \
uint8_t SWAP = p1; \
p1 = p2; \
p2 = SWAP; \
} while (0)
void rad1o_drawHLine(uint8_t y, uint8_t x1, uint8_t x2, uint8_t color)
{
if (x1 > x2) {
SWAP(x1, x2);
}
for (uint8_t i = x1; i <= x2; ++i) {
rad1o_lcdSetPixel(i, y, color);
}
}
void rad1o_drawVLine(uint8_t x, uint8_t y1, uint8_t y2, uint8_t color)
{
if (y1 > y2) {
SWAP(y1, y2);
}
for (uint8_t i = y1; i <= y2; ++i) {
rad1o_lcdSetPixel(x, i, color);
}
}

View File

@ -0,0 +1,9 @@
#ifndef __RAD1O_DRAW_H__
#define __RAD1O_DRAW_H__
#include <stdint.h>
void rad1o_drawHLine(uint8_t y, uint8_t x1, uint8_t x2, uint8_t color);
void rad1o_drawVLine(uint8_t x, uint8_t y1, uint8_t y2, uint8_t color);
#endif

View File

@ -0,0 +1,35 @@
#ifndef __RAD1O_FONTS_H__
#define __RAD1O_FONTS_H__
#include <stdint.h>
/* Partially based on original code for the KS0108 by Stephane Rey */
/* Based on code code by Kevin Townsend */
typedef struct {
const uint8_t widthBits; // width, in bits (or pixels), of the character
} FONT_CHAR_INFO;
struct FONT_DEF {
uint8_t u8Width; /* Character width for storage */
uint8_t u8Height; /* Character height for storage */
uint8_t u8FirstChar; /* The first character available */
uint8_t u8LastChar; /* The last character available */
const uint8_t *au8FontTable; /* Font table start address in memory */
const FONT_CHAR_INFO *charInfo; /* Pointer to array of char information */
const uint16_t *charExtra; /* Pointer to array of extra char info */
};
struct EXTFONT {
uint8_t type; // 0: none, 1: static, 2: loaded
char name[13];
struct FONT_DEF def;
};
typedef const struct FONT_DEF *FONT;
#define FONT_DEFAULT 0
#define FONT_INTERNAL 1
#define FONT_EXTERNAL 2
#endif

View File

@ -0,0 +1,43 @@
#include "print.h"
#include "display.h"
#include "fonts.h"
#include "render.h"
#include "smallfonts.h"
static int32_t x = 0;
static int32_t y = 0;
void rad1o_lcdPrint(const char *string)
{
x = rad1o_DoString(x, y, string);
}
void rad1o_lcdNl(void)
{
x = 0;
y += rad1o_getFontHeight();
}
void rad1o_lcdClear(void)
{
x = 0;
y = 0;
rad1o_lcdFill(0xff);
}
void rad1o_lcdMoveCrsr(int32_t dx, int32_t dy)
{
x += dx;
y += dy;
}
void rad1o_lcdSetCrsr(int32_t dx, int32_t dy)
{
x = dx;
y = dy;
}
void rad1o_setSystemFont(void)
{
rad1o_setIntFont(&Font_7x8);
}

View File

@ -0,0 +1,13 @@
#ifndef __RAD1O_PRINT_H__
#define __RAD1O_PRINT_H__
#include <stdint.h>
void rad1o_lcdPrint(const char *string);
void rad1o_lcdNl(void);
void rad1o_lcdClear(void);
void rad1o_lcdMoveCrsr(int32_t dx, int32_t dy);
void rad1o_lcdSetCrsr(int32_t dx, int32_t dy);
void rad1o_setSystemFont(void);
#endif

View File

@ -0,0 +1,162 @@
#include "render.h"
#include "decoder.h"
#include "display.h"
#include "fonts.h"
#include "smallfonts.h"
#include <string.h>
/* Global Variables */
static const struct FONT_DEF *font = NULL;
static struct EXTFONT efont;
static uint8_t color_bg = 0xff; /* background color */
static uint8_t color_fg = 0x00; /* foreground color */
/* Exported Functions */
void rad1o_setTextColor(uint8_t bg, uint8_t fg)
{
color_bg = bg;
color_fg = fg;
}
void rad1o_setIntFont(const struct FONT_DEF *newfont)
{
memcpy(&efont.def, newfont, sizeof(struct FONT_DEF));
efont.type = FONT_INTERNAL;
font = &efont.def;
}
int rad1o_getFontHeight(void)
{
if (font)
return font->u8Height;
return 8; // XXX: Should be done right.
}
static int _getIndex(int c)
{
#define ERRCHR (font->u8FirstChar + 1)
/* Does this font provide this character? */
if (c < font->u8FirstChar)
c = ERRCHR;
if (c > font->u8LastChar && efont.type != FONT_EXTERNAL &&
font->charExtra == NULL)
c = ERRCHR;
if (c > font->u8LastChar &&
(efont.type == FONT_EXTERNAL || font->charExtra != NULL)) {
int cc = 0;
while (font->charExtra[cc] < c)
cc++;
if (font->charExtra[cc] > c)
c = ERRCHR;
else
c = font->u8LastChar + cc + 1;
};
c -= font->u8FirstChar;
return c;
}
int rad1o_DoChar(int sx, int sy, int c)
{
if (font == NULL) {
font = &Font_7x8;
};
/* how many bytes is it high? */
char height = (font->u8Height - 1) / 8 + 1;
char hoff = (8 - (font->u8Height % 8)) % 8;
const uint8_t *data;
int width, preblank = 0, postblank = 0;
do { /* Get Character data */
/* Get intex into character list */
c = _getIndex(c);
/* starting offset into character source data */
int toff = 0;
if (font->u8Width == 0) {
for (int y = 0; y < c; y++)
toff += font->charInfo[y].widthBits;
width = font->charInfo[c].widthBits;
toff *= height;
data = &font->au8FontTable[toff];
postblank = 1;
} else if (font->u8Width == 1) { // NEW CODE
// Find offset and length for our character
for (int y = 0; y < c; y++)
toff += font->charInfo[y].widthBits;
width = font->charInfo[c].widthBits;
if (font->au8FontTable[toff] >> 4 ==
15) { // It's a raw character!
preblank = font->au8FontTable[toff + 1];
postblank = font->au8FontTable[toff + 2];
data = &font->au8FontTable[toff + 3];
width = (width - 3 / height);
} else {
data = rad1o_pk_decode(
&font->au8FontTable[toff], &width);
}
} else {
toff = (c)*font->u8Width * 1;
width = font->u8Width;
data = &font->au8FontTable[toff];
};
} while (0);
#define xy_(x, y) \
((x < 0 || y < 0 || x >= RESX || y >= RESY) ? 0 : (y)*RESX + (x))
#define gPx(x, y) (data[x * height + (height - y / 8 - 1)] & (1 << (y % 8)))
int x = 0;
/* Fonts may not be byte-aligned, shift up so the top matches */
sy -= hoff;
sx += preblank;
uint8_t *lcdBuffer = rad1o_lcdGetBuffer();
/* per line */
for (int y = hoff; y < height * 8; y++) {
if (sy + y >= RESY)
continue;
/* Optional: empty space to the left */
for (int b = 1; b <= preblank; b++) {
if (sx >= RESX)
continue;
lcdBuffer[xy_(sx - b, sy + y)] = color_bg;
};
/* Render character */
for (x = 0; x < width; x++) {
if (sx + x >= RESX)
continue;
if (gPx(x, y)) {
lcdBuffer[xy_(sx + x, sy + y)] = color_fg;
} else {
lcdBuffer[xy_(sx + x, sy + y)] = color_bg;
};
};
/* Optional: empty space to the right */
for (int m = 0; m < postblank; m++) {
if (sx + x + m >= RESX)
continue;
lcdBuffer[xy_(sx + x + m, sy + y)] = color_bg;
};
};
return sx + (width + postblank);
}
int rad1o_DoString(int sx, int sy, const char *s)
{
const char *c;
for (c = s; *c != 0; c++) {
sx = rad1o_DoChar(sx, sy, *c);
};
return sx;
}

View File

@ -0,0 +1,11 @@
#ifndef __RENDER_H_
#define __RENDER_H_
#include "fonts.h"
void rad1o_setTextColor(uint8_t bg, uint8_t fg);
void rad1o_setIntFont(const struct FONT_DEF *font);
int rad1o_getFontHeight(void);
int rad1o_DoString(int sx, int sy, const char *s);
int rad1o_DoChar(int sx, int sy, int c);
#endif

View File

@ -0,0 +1,144 @@
/* Partially based on original code for the KS0108 by Stephane Rey */
/**************************************************************************/
/*!
@file smallfonts.c
@author K. Townsend (microBuilder.eu)
@date 22 March 2010
@version 0.10
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2010, microBuilder SARL
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#include "smallfonts.h"
/* System 7x8 */
const uint8_t au8Font7x8[] = {
0, 0, 0, 0, 0, 0, 0, //' '
0, 6, 95, 95, 6, 0, 0, //'!'
0, 7, 7, 0, 7, 7, 0, //'"'
20, 127, 127, 20, 127, 127, 20, //'#'
36, 46, 107, 107, 58, 18, 0, //'$'
70, 102, 48, 24, 12, 102, 98, //'%'
48, 122, 79, 93, 55, 122, 72, //'&'
4, 7, 3, 0, 0, 0, 0, //'''
0, 28, 62, 99, 65, 0, 0, //'('
0, 65, 99, 62, 28, 0, 0, //')'
8, 42, 62, 28, 28, 62, 42, //'*'
8, 8, 62, 62, 8, 8, 0, //'+'
0, 128, 224, 96, 0, 0, 0, //','
8, 8, 8, 8, 8, 8, 0, //'-'
0, 0, 96, 96, 0, 0, 0, //'.'
96, 48, 24, 12, 6, 3, 1, //'/'
62, 127, 113, 89, 77, 127, 62, //'0'
64, 66, 127, 127, 64, 64, 0, //'1'
98, 115, 89, 73, 111, 102, 0, //'2'
34, 99, 73, 73, 127, 54, 0, //'3'
24, 28, 22, 83, 127, 127, 80, //'4'
39, 103, 69, 69, 125, 57, 0, //'5'
60, 126, 75, 73, 121, 48, 0, //'6'
3, 3, 113, 121, 15, 7, 0, //'7'
54, 127, 73, 73, 127, 54, 0, //'8'
6, 79, 73, 105, 63, 30, 0, //'9'
0, 0, 102, 102, 0, 0, 0, //':'
0, 128, 230, 102, 0, 0, 0, //';'
8, 28, 54, 99, 65, 0, 0, //'<'
36, 36, 36, 36, 36, 36, 0, //'='
0, 65, 99, 54, 28, 8, 0, //'>'
2, 3, 81, 89, 15, 6, 0, //'?'
62, 127, 65, 93, 93, 31, 30, //'@'
124, 126, 19, 19, 126, 124, 0, //'A'
65, 127, 127, 73, 73, 127, 54, //'B'
28, 62, 99, 65, 65, 99, 34, //'C'
65, 127, 127, 65, 99, 62, 28, //'D'
65, 127, 127, 73, 93, 65, 99, //'E'
65, 127, 127, 73, 29, 1, 3, //'F'
28, 62, 99, 65, 81, 115, 114, //'G'
127, 127, 8, 8, 127, 127, 0, //'H'
0, 65, 127, 127, 65, 0, 0, //'I'
48, 112, 64, 65, 127, 63, 1, //'J'
65, 127, 127, 8, 28, 119, 99, //'K'
65, 127, 127, 65, 64, 96, 112, //'L'
127, 127, 14, 28, 14, 127, 127, //'M'
127, 127, 6, 12, 24, 127, 127, //'N'
28, 62, 99, 65, 99, 62, 28, //'O'
65, 127, 127, 73, 9, 15, 6, //'P'
30, 63, 33, 113, 127, 94, 0, //'Q'
65, 127, 127, 9, 25, 127, 102, //'R'
38, 111, 77, 89, 115, 50, 0, //'S'
3, 65, 127, 127, 65, 3, 0, //'T'
127, 127, 64, 64, 127, 127, 0, //'U'
31, 63, 96, 96, 63, 31, 0, //'V'
127, 127, 48, 24, 48, 127, 127, //'W'
67, 103, 60, 24, 60, 103, 67, //'X'
7, 79, 120, 120, 79, 7, 0, //'Y'
71, 99, 113, 89, 77, 103, 115, //'Z'
0, 127, 127, 65, 65, 0, 0, //'['
1, 3, 6, 12, 24, 48, 96, //'\'
0, 65, 65, 127, 127, 0, 0, //']'
8, 12, 6, 3, 6, 12, 8, //'^'
128, 128, 128, 128, 128, 128, 128, //'_'
0, 0, 3, 7, 4, 0, 0, //'`'
32, 116, 84, 84, 60, 120, 64, //'a'
65, 127, 63, 72, 72, 120, 48, //'b'
56, 124, 68, 68, 108, 40, 0, //'c'
48, 120, 72, 73, 63, 127, 64, //'d'
56, 124, 84, 84, 92, 24, 0, //'e'
72, 126, 127, 73, 3, 2, 0, //'f'
56, 188, 164, 164, 252, 120, 0, //'g'
65, 127, 127, 8, 4, 124, 120, //'h'
0, 68, 125, 125, 64, 0, 0, //'i'
96, 224, 128, 128, 253, 125, 0, //'j'
65, 127, 127, 16, 56, 108, 68, //'k'
0, 65, 127, 127, 64, 0, 0, //'l'
120, 124, 28, 56, 28, 124, 120, //'m'
124, 124, 4, 4, 124, 120, 0, //'n'
56, 124, 68, 68, 124, 56, 0, //'o'
0, 252, 252, 164, 36, 60, 24, //'p'
24, 60, 36, 164, 248, 252, 132, //'q'
68, 124, 120, 76, 4, 28, 24, //'r'
72, 92, 84, 84, 116, 36, 0, //'s'
0, 4, 62, 127, 68, 36, 0, //'t'
60, 124, 64, 64, 60, 124, 64, //'u'
28, 60, 96, 96, 60, 28, 0, //'v'
60, 124, 112, 56, 112, 124, 60, //'w'
68, 108, 56, 16, 56, 108, 68, //'x'
60, 188, 160, 160, 252, 124, 0, //'y'
76, 100, 116, 92, 76, 100, 0, //'z'
8, 8, 62, 119, 65, 65, 0, //'{'
0, 0, 0, 119, 119, 0, 0, //'|'
65, 65, 119, 62, 8, 8, 0, //'}'
2, 3, 1, 3, 2, 3, 1, //'~'
255, 129, 129, 129, 129, 129, 255, //'^?'
14, 159, 145, 177, 251, 74, 0 //'?'
};
/* Global variables */
const struct FONT_DEF Font_7x8 = { 7, 8, 32, 128, au8Font7x8, NULL, NULL };

View File

@ -0,0 +1,51 @@
/**************************************************************************/
/*!
@file smallfonts.h
@author K. Townsend (microBuilder.eu)
@date 22 March 2010
@version 0.10
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2010, microBuilder SARL
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#ifndef __RAD1O_SMALLFONTS_H__
#define __RAD1O_SMALLFONTS_H__
#include "fonts.h"
#include <stddef.h>
#include <stdint.h>
/* Partially based on original code for the KS0108 by Stephane Rey */
/* Current version by Kevin Townsend */
extern const struct FONT_DEF Font_7x8;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
#ifndef __RAD1O_UBUNTU18_H__
#define __RAD1O_UBUNTU18_H__
#include "fonts.h"
extern const struct FONT_DEF Font_Ubuntu18pt;
#endif

View File

@ -0,0 +1,454 @@
/*
* 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/scu.h>
#include <hackrf_core.h>
#include "hackrf_ui.h"
#include <mixer.h>
#include <max2837.h>
#include <max5864.h>
#include <sgpio.h>
#if (defined JAWBREAKER || defined HACKRF_ONE || defined RAD1O)
/*
* 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.
*
* The rad1o also uses GPIO pins to control the different switches. The amplifiers
* are also connected to the LPC.
*/
#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;
/*
* Antenna port power on HackRF One is controlled by GPO1 on the RFFC5072.
* This is the only thing we use RFFC5072 GPO for on HackRF One. The value of
* SWITCHCTRL_NO_ANT_PWR does not correspond to the GPO1 bit in the gpo
* register.
*/
#define SWITCHCTRL_ANT_PWR (1 << 6) /* turn on antenna port power */
#ifdef HACKRF_ONE
static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) {
if (ctrl & SWITCHCTRL_TX) {
gpio_set(rf_path->gpio_tx);
gpio_clear(rf_path->gpio_rx);
} else {
gpio_clear(rf_path->gpio_tx);
gpio_set(rf_path->gpio_rx);
}
if (ctrl & SWITCHCTRL_MIX_BYPASS) {
gpio_set(rf_path->gpio_mix_bypass);
gpio_clear(rf_path->gpio_no_mix_bypass);
if (ctrl & SWITCHCTRL_TX) {
gpio_set(rf_path->gpio_tx_mix_bp);
gpio_clear(rf_path->gpio_rx_mix_bp);
} else {
gpio_clear(rf_path->gpio_tx_mix_bp);
gpio_set(rf_path->gpio_rx_mix_bp);
}
} else {
gpio_clear(rf_path->gpio_mix_bypass);
gpio_set(rf_path->gpio_no_mix_bypass);
gpio_clear(rf_path->gpio_tx_mix_bp);
gpio_clear(rf_path->gpio_rx_mix_bp);
}
if (ctrl & SWITCHCTRL_HP) {
gpio_set(rf_path->gpio_hp);
gpio_clear(rf_path->gpio_lp);
} else {
gpio_clear(rf_path->gpio_hp);
gpio_set(rf_path->gpio_lp);
}
if (ctrl & SWITCHCTRL_AMP_BYPASS) {
gpio_set(rf_path->gpio_amp_bypass);
gpio_clear(rf_path->gpio_tx_amp);
gpio_set(rf_path->gpio_no_tx_amp_pwr);
gpio_clear(rf_path->gpio_rx_amp);
gpio_set(rf_path->gpio_no_rx_amp_pwr);
} else if (ctrl & SWITCHCTRL_TX) {
gpio_clear(rf_path->gpio_amp_bypass);
gpio_set(rf_path->gpio_tx_amp);
gpio_clear(rf_path->gpio_no_tx_amp_pwr);
gpio_clear(rf_path->gpio_rx_amp);
gpio_set(rf_path->gpio_no_rx_amp_pwr);
} else {
gpio_clear(rf_path->gpio_amp_bypass);
gpio_clear(rf_path->gpio_tx_amp);
gpio_set(rf_path->gpio_no_tx_amp_pwr);
gpio_set(rf_path->gpio_rx_amp);
gpio_clear(rf_path->gpio_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(rf_path->gpio_no_tx_amp_pwr);
if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR)
gpio_set(rf_path->gpio_no_rx_amp_pwr);
if (ctrl & SWITCHCTRL_ANT_PWR) {
mixer_set_gpo(&mixer, 0x00); /* turn on antenna power by clearing GPO1 */
} else {
mixer_set_gpo(&mixer, 0x01); /* turn off antenna power by setting GPO1 */
}
}
#endif
#ifdef RAD1O
static void switchctrl_set_rad1o(rf_path_t* const rf_path, uint8_t ctrl) {
if (ctrl & SWITCHCTRL_TX) {
gpio_set(rf_path->gpio_tx_rx_n);
gpio_clear(rf_path->gpio_tx_rx);
} else {
gpio_clear(rf_path->gpio_tx_rx_n);
gpio_set(rf_path->gpio_tx_rx);
}
if (ctrl & SWITCHCTRL_MIX_BYPASS) {
gpio_clear(rf_path->gpio_by_mix);
gpio_set(rf_path->gpio_by_mix_n);
gpio_clear(rf_path->gpio_mixer_en);
} else {
gpio_set(rf_path->gpio_by_mix);
gpio_clear(rf_path->gpio_by_mix_n);
gpio_set(rf_path->gpio_mixer_en);
}
if (ctrl & SWITCHCTRL_HP) {
gpio_set(rf_path->gpio_low_high_filt);
gpio_clear(rf_path->gpio_low_high_filt_n);
} else {
gpio_clear(rf_path->gpio_low_high_filt);
gpio_set(rf_path->gpio_low_high_filt_n);
}
if (ctrl & SWITCHCTRL_AMP_BYPASS) {
gpio_clear(rf_path->gpio_by_amp);
gpio_set(rf_path->gpio_by_amp_n);
gpio_clear(rf_path->gpio_tx_amp);
gpio_clear(rf_path->gpio_rx_lna);
} else if (ctrl & SWITCHCTRL_TX) {
gpio_set(rf_path->gpio_by_amp);
gpio_clear(rf_path->gpio_by_amp_n);
gpio_set(rf_path->gpio_tx_amp);
gpio_clear(rf_path->gpio_rx_lna);
} else {
gpio_set(rf_path->gpio_by_amp);
gpio_clear(rf_path->gpio_by_amp_n);
gpio_clear(rf_path->gpio_tx_amp);
gpio_set(rf_path->gpio_rx_lna);
}
/*
* 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_clear(rf_path->gpio_tx_amp);
}
if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR) {
gpio_clear(rf_path->gpio_rx_lna);
}
}
#endif
static void switchctrl_set(rf_path_t* const rf_path, const uint8_t gpo) {
#ifdef JAWBREAKER
(void) rf_path; /* silence unused param warning */
mixer_set_gpo(&mixer, gpo);
#elif HACKRF_ONE
switchctrl_set_hackrf_one(rf_path, gpo);
#elif RAD1O
switchctrl_set_rad1o(rf_path, gpo);
#else
(void)gpo;
#endif
}
void rf_path_pin_setup(rf_path_t* const rf_path) {
#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 */
gpio_output(rf_path->gpio_amp_bypass);
gpio_output(rf_path->gpio_no_mix_bypass);
gpio_output(rf_path->gpio_rx_amp);
gpio_output(rf_path->gpio_no_rx_amp_pwr);
gpio_output(rf_path->gpio_hp);
gpio_output(rf_path->gpio_lp);
gpio_output(rf_path->gpio_tx_mix_bp);
gpio_output(rf_path->gpio_rx_mix_bp);
gpio_output(rf_path->gpio_tx_amp);
gpio_output(rf_path->gpio_no_tx_amp_pwr);
gpio_output(rf_path->gpio_tx);
gpio_output(rf_path->gpio_mix_bypass);
gpio_output(rf_path->gpio_rx);
/*
* Safe (initial) switch settings turn off both amplifiers and antenna port
* power and enable both amp bypass and mixer bypass.
*/
switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS);
#elif RAD1O
/* Configure RF switch control signals */
scu_pinmux(SCU_BY_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_BY_AMP_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_TX_RX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_TX_RX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_BY_MIX, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_BY_MIX_N, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_LOW_HIGH_FILT, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_LOW_HIGH_FILT_N,SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_TX_AMP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_RX_LNA, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_MIXER_EN, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
/* Configure RF power supply (VAA) switch */
scu_pinmux(SCU_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
/* Configure RF switch control signals as outputs */
gpio_output(rf_path->gpio_tx_rx_n);
gpio_output(rf_path->gpio_tx_rx);
gpio_output(rf_path->gpio_by_mix);
gpio_output(rf_path->gpio_by_mix_n);
gpio_output(rf_path->gpio_by_amp);
gpio_output(rf_path->gpio_by_amp_n);
gpio_output(rf_path->gpio_mixer_en);
gpio_output(rf_path->gpio_low_high_filt);
gpio_output(rf_path->gpio_low_high_filt_n);
gpio_output(rf_path->gpio_tx_amp);
gpio_output(rf_path->gpio_rx_lna);
/*
* Safe (initial) switch settings turn off both amplifiers and antenna port
* power and enable both amp bypass and mixer bypass.
*/
switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS);
#else
(void) rf_path; /* silence unused param warning */
#endif
}
void rf_path_init(rf_path_t* const rf_path) {
ssp1_set_mode_max5864();
max5864_setup(&max5864);
max5864_shutdown(&max5864);
ssp1_set_mode_max2837();
max2837_setup(&max2837);
max2837_start(&max2837);
mixer_setup(&mixer);
switchctrl_set(rf_path, switchctrl);
}
void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t direction) {
/* Turn off TX and RX amplifiers, then enable based on direction and bypass state. */
rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
switch(direction) {
case RF_PATH_DIRECTION_TX:
rf_path->switchctrl |= SWITCHCTRL_TX;
if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
/* TX amplifier is in path, be sure to enable TX amplifier. */
rf_path->switchctrl &= ~SWITCHCTRL_NO_TX_AMP_PWR;
}
mixer_tx(&mixer);
if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
mixer_disable(&mixer);
} else {
mixer_enable(&mixer);
}
ssp1_set_mode_max5864();
max5864_tx(&max5864);
ssp1_set_mode_max2837();
max2837_tx(&max2837);
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX);
break;
case RF_PATH_DIRECTION_RX:
rf_path->switchctrl &= ~SWITCHCTRL_TX;
if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
/* RX amplifier is in path, be sure to enable RX amplifier. */
rf_path->switchctrl &= ~SWITCHCTRL_NO_RX_AMP_PWR;
}
mixer_rx(&mixer);
if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
mixer_disable(&mixer);
} else {
mixer_enable(&mixer);
}
ssp1_set_mode_max5864();
max5864_rx(&max5864);
ssp1_set_mode_max2837();
max2837_rx(&max2837);
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
break;
case RF_PATH_DIRECTION_OFF:
default:
#ifdef HACKRF_ONE
rf_path_set_antenna(rf_path, 0);
#endif
rf_path_set_lna(rf_path, 0);
/* Set RF path to receive direction when "off" */
rf_path->switchctrl &= ~SWITCHCTRL_TX;
mixer_disable(&mixer);
ssp1_set_mode_max5864();
max5864_standby(&max5864);
ssp1_set_mode_max2837();
max2837_set_mode(&max2837, MAX2837_MODE_STANDBY);
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
break;
}
switchctrl_set(rf_path, rf_path->switchctrl);
hackrf_ui()->set_direction(direction);
}
void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) {
switch(filter) {
default:
case RF_PATH_FILTER_BYPASS:
rf_path->switchctrl |= SWITCHCTRL_MIX_BYPASS;
mixer_disable(&mixer);
break;
case RF_PATH_FILTER_LOW_PASS:
rf_path->switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
mixer_enable(&mixer);
break;
case RF_PATH_FILTER_HIGH_PASS:
rf_path->switchctrl &= ~SWITCHCTRL_MIX_BYPASS;
rf_path->switchctrl |= SWITCHCTRL_HP;
mixer_enable(&mixer);
break;
}
switchctrl_set(rf_path, rf_path->switchctrl);
hackrf_ui()->set_filter(filter);
}
void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable) {
if( enable ) {
if( rf_path->switchctrl & SWITCHCTRL_TX ) {
/* AMP_BYPASS=0, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=0 */
rf_path->switchctrl |= SWITCHCTRL_NO_RX_AMP_PWR;
rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR);
} else {
/* AMP_BYPASS=0, NO_RX_AMP_PWR=0, NO_TX_AMP_PWR=1 */
rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR;
rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_RX_AMP_PWR);
}
} else {
/* AMP_BYPASS=1, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=1 */
rf_path->switchctrl |= SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
}
switchctrl_set(rf_path, rf_path->switchctrl);
hackrf_ui()->set_lna_power(enable);
}
/* antenna port power control */
void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable) {
if (enable) {
rf_path->switchctrl |= SWITCHCTRL_ANT_PWR;
} else {
rf_path->switchctrl &= ~(SWITCHCTRL_ANT_PWR);
}
switchctrl_set(rf_path, rf_path->switchctrl);
hackrf_ui()->set_antenna_bias(enable);
}

View File

@ -0,0 +1,84 @@
/*
* 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>
#include "gpio.h"
typedef enum {
RF_PATH_DIRECTION_OFF,
RF_PATH_DIRECTION_RX,
RF_PATH_DIRECTION_TX,
} rf_path_direction_t;
typedef enum {
RF_PATH_FILTER_BYPASS = 0,
RF_PATH_FILTER_LOW_PASS = 1,
RF_PATH_FILTER_HIGH_PASS = 2,
} rf_path_filter_t;
typedef struct rf_path_t {
uint8_t switchctrl;
#ifdef HACKRF_ONE
gpio_t gpio_hp;
gpio_t gpio_lp;
gpio_t gpio_tx_mix_bp;
gpio_t gpio_no_mix_bypass;
gpio_t gpio_rx_mix_bp;
gpio_t gpio_tx_amp;
gpio_t gpio_tx;
gpio_t gpio_mix_bypass;
gpio_t gpio_rx;
gpio_t gpio_no_tx_amp_pwr;
gpio_t gpio_amp_bypass;
gpio_t gpio_rx_amp;
gpio_t gpio_no_rx_amp_pwr;
#endif
#ifdef RAD1O
gpio_t gpio_tx_rx_n;
gpio_t gpio_tx_rx;
gpio_t gpio_by_mix;
gpio_t gpio_by_mix_n;
gpio_t gpio_by_amp;
gpio_t gpio_by_amp_n;
gpio_t gpio_mixer_en;
gpio_t gpio_low_high_filt;
gpio_t gpio_low_high_filt_n;
gpio_t gpio_tx_amp;
gpio_t gpio_rx_lna;
#endif
} rf_path_t;
void rf_path_pin_setup(rf_path_t* const rf_path);
void rf_path_init(rf_path_t* const rf_path);
void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t direction);
void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter);
void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable);
void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable);
#endif/*__RFPATH_H__*/

View File

@ -0,0 +1,287 @@
/*
* Copyright 2012 Michael Ossmann
* Copyright 2014 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.
*/
/*
* 'gcc -DTEST -DDEBUG -O2 -o test rffc5071.c' prints out what test
* program would do if it had a real spi library
*/
/*
* The actual part on Jawbreaker is the RFFC5072, not the RFFC5071, but the
* RFFC5071 may be installed instead. The only difference between the parts is
* that the RFFC5071 includes a second mixer.
*/
#include <stdint.h>
#include <string.h>
#include "rffc5071.h"
#include "rffc5071_regs.def" // private register def macros
#include "hackrf_core.h"
/* Default register values. */
static const uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = {
0xbefa, /* 00 */
0x4064, /* 01 */
0x9055, /* 02 */
0x2d02, /* 03 */
0xacbf, /* 04 */
0xacbf, /* 05 */
0x0028, /* 06 */
0x0028, /* 07 */
0xff00, /* 08 */
0x8220, /* 09 */
0x0202, /* 0A */
0x4800, /* 0B */
0x1a94, /* 0C */
0xd89d, /* 0D */
0x8900, /* 0E */
0x1e84, /* 0F */
0x89d8, /* 10 */
0x9d00, /* 11 */
0x2a20, /* 12 */
0x0000, /* 13 */
0x0000, /* 14 */
0x0000, /* 15 */
0x0000, /* 16 */
0x4900, /* 17 */
0x0281, /* 18 */
0xf00f, /* 19 */
0x0000, /* 1A */
0x0000, /* 1B */
0xc840, /* 1C */
0x1000, /* 1D */
0x0005, /* 1E */ };
/* Set up all registers according to defaults specified in docs. */
void rffc5071_init(rffc5071_driver_t* const drv)
{
memcpy(drv->regs, rffc5071_regs_default, sizeof(drv->regs));
drv->regs_dirty = 0x7fffffff;
/* Write default register values to chip. */
rffc5071_regs_commit(drv);
}
/*
* Set up pins for GPIO and SPI control, configure SSP peripheral for SPI, and
* set our own default register configuration.
*/
void rffc5071_setup(rffc5071_driver_t* const drv)
{
gpio_set(drv->gpio_reset);
gpio_output(drv->gpio_reset);
rffc5071_init(drv);
/* initial setup */
/* put zeros in freq contol registers */
set_RFFC5071_P2N(drv, 0);
set_RFFC5071_P2LODIV(drv, 0);
set_RFFC5071_P2PRESC(drv, 0);
set_RFFC5071_P2VCOSEL(drv, 0);
set_RFFC5071_P2N(drv, 0);
set_RFFC5071_P2LODIV(drv, 0);
set_RFFC5071_P2PRESC(drv, 0);
set_RFFC5071_P2VCOSEL(drv, 0);
set_RFFC5071_P2N(drv, 0);
set_RFFC5071_P2LODIV(drv, 0);
set_RFFC5071_P2PRESC(drv, 0);
set_RFFC5071_P2VCOSEL(drv, 0);
/* set ENBL and MODE to be configured via 3-wire interface,
* not control pins. */
set_RFFC5071_SIPIN(drv, 1);
/* GPOs are active at all times */
set_RFFC5071_GATE(drv, 1);
rffc5071_regs_commit(drv);
}
static uint16_t rffc5071_spi_read(rffc5071_driver_t* const drv, uint8_t r) {
(void)drv;
uint16_t data[] = { 0x80 | (r & 0x7f), 0xffff };
spi_bus_transfer(drv->bus, data, 2);
return data[1];
}
static void rffc5071_spi_write(rffc5071_driver_t* const drv, uint8_t r, uint16_t v) {
(void)drv;
uint16_t data[] = { 0x00 | (r & 0x7f), v };
spi_bus_transfer(drv->bus, data, 2);
}
uint16_t rffc5071_reg_read(rffc5071_driver_t* const drv, uint8_t r)
{
/* Readback register is not cached. */
if (r == RFFC5071_READBACK_REG)
return rffc5071_spi_read(drv, r);
/* Discard uncommited write when reading. This shouldn't
* happen, and probably has not been tested. */
if ((drv->regs_dirty >> r) & 0x1) {
drv->regs[r] = rffc5071_spi_read(drv, r);
};
return drv->regs[r];
}
void rffc5071_reg_write(rffc5071_driver_t* const drv, uint8_t r, uint16_t v)
{
drv->regs[r] = v;
rffc5071_spi_write(drv, r, v);
RFFC5071_REG_SET_CLEAN(drv, r);
}
static inline void rffc5071_reg_commit(rffc5071_driver_t* const drv, uint8_t r)
{
rffc5071_reg_write(drv, r, drv->regs[r]);
}
void rffc5071_regs_commit(rffc5071_driver_t* const drv)
{
int r;
for(r = 0; r < RFFC5071_NUM_REGS; r++) {
if ((drv->regs_dirty >> r) & 0x1) {
rffc5071_reg_commit(drv, r);
}
}
}
void rffc5071_tx(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_FULLD(drv, 0);
set_RFFC5071_MODE(drv, 1); /* mixer 2 used for both RX and TX */
rffc5071_regs_commit(drv);
}
void rffc5071_rx(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_FULLD(drv, 0);
set_RFFC5071_MODE(drv, 1); /* mixer 2 used for both RX and TX */
rffc5071_regs_commit(drv);
}
/*
* This function turns on both mixer (full-duplex) on the RFFC5071, but our
* current hardware designs do not support full-duplex operation.
*/
void rffc5071_rxtx(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_FULLD(drv, 1); /* mixer 1 and mixer 2 (RXTX) */
rffc5071_regs_commit(drv);
rffc5071_enable(drv);
}
void rffc5071_disable(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 0);
rffc5071_regs_commit(drv);
}
void rffc5071_enable(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 1);
rffc5071_regs_commit(drv);
}
#define LO_MAX 5400
#define REF_FREQ 40
#define FREQ_ONE_MHZ (1000*1000)
/* configure frequency synthesizer in integer mode (lo in MHz) */
uint64_t rffc5071_config_synth_int(rffc5071_driver_t* const drv, uint16_t lo) {
uint8_t lodiv;
uint16_t fvco;
uint8_t fbkdiv;
uint16_t n;
uint64_t tune_freq_hz;
uint16_t p1nmsb;
uint8_t p1nlsb;
/* Calculate n_lo */
uint8_t n_lo = 0;
uint16_t x = LO_MAX / lo;
while ((x > 1) && (n_lo < 5)) {
n_lo++;
x >>= 1;
}
lodiv = 1 << n_lo;
fvco = lodiv * lo;
/* higher divider and charge pump current required above
* 3.2GHz. Programming guide says these values (fbkdiv, n,
* maybe pump?) can be changed back after enable in order to
* improve phase noise, since the VCO will already be stable
* and will be unaffected. */
if (fvco > 3200) {
fbkdiv = 4;
set_RFFC5071_PLLCPL(drv, 3);
} else {
fbkdiv = 2;
set_RFFC5071_PLLCPL(drv, 2);
}
uint64_t tmp_n = ((uint64_t)fvco << 29ULL) / (fbkdiv*REF_FREQ) ;
n = tmp_n >> 29ULL;
p1nmsb = (tmp_n >> 13ULL) & 0xffff;
p1nlsb = (tmp_n >> 5ULL) & 0xff;
tune_freq_hz = (REF_FREQ * (tmp_n >> 5ULL) * fbkdiv * FREQ_ONE_MHZ)
/ (lodiv * (1 << 24ULL));
/* Path 2 */
set_RFFC5071_P2LODIV(drv, n_lo);
set_RFFC5071_P2N(drv, n);
set_RFFC5071_P2PRESC(drv, fbkdiv >> 1);
set_RFFC5071_P2NMSB(drv, p1nmsb);
set_RFFC5071_P2NLSB(drv, p1nlsb);
rffc5071_regs_commit(drv);
return tune_freq_hz;
}
/* !!!!!!!!!!! hz is currently ignored !!!!!!!!!!! */
uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, uint16_t mhz) {
uint32_t tune_freq;
rffc5071_disable(drv);
tune_freq = rffc5071_config_synth_int(drv, mhz);
rffc5071_enable(drv);
return tune_freq;
}
void rffc5071_set_gpo(rffc5071_driver_t* const drv, uint8_t gpo)
{
/* We set GPO for both paths just in case. */
set_RFFC5071_P1GPO(drv, gpo);
set_RFFC5071_P2GPO(drv, gpo);
rffc5071_regs_commit(drv);
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 2012 Michael Ossmann
* Copyright 2014 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 __RFFC5071_H
#define __RFFC5071_H
#include <stdint.h>
#include "spi_bus.h"
#include "gpio.h"
/* 31 registers, each containing 16 bits of data. */
#define RFFC5071_NUM_REGS 31
typedef struct {
spi_bus_t* const bus;
gpio_t gpio_reset;
uint16_t regs[RFFC5071_NUM_REGS];
uint32_t regs_dirty;
} rffc5071_driver_t;
/* Initialize chip. Call _setup() externally, as it calls _init(). */
extern void rffc5071_init(rffc5071_driver_t* const drv);
extern void rffc5071_setup(rffc5071_driver_t* const drv);
/* Read a register via SPI. Save a copy to memory and return
* value. Discard any uncommited changes and mark CLEAN. */
extern uint16_t rffc5071_reg_read(rffc5071_driver_t* const drv, uint8_t r);
/* Write value to register via SPI and save a copy to memory. Mark
* CLEAN. */
extern void rffc5071_reg_write(rffc5071_driver_t* const drv, uint8_t r, uint16_t v);
/* Write all dirty registers via SPI from memory. Mark all clean. Some
* operations require registers to be written in a certain order. Use
* provided routines for those operations. */
extern void rffc5071_regs_commit(rffc5071_driver_t* const drv);
/* Set frequency (MHz). */
extern uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, 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(rffc5071_driver_t* const drv);
extern void rffc5071_rx(rffc5071_driver_t* const drv);
extern void rffc5071_rxtx(rffc5071_driver_t* const drv);
extern void rffc5071_enable(rffc5071_driver_t* const drv);
extern void rffc5071_disable(rffc5071_driver_t* const drv);
extern void rffc5071_set_gpo(rffc5071_driver_t* const drv, uint8_t);
#endif // __RFFC5071_H

View File

@ -0,0 +1,260 @@
/* -*- mode: c -*-
*
* Copyright 2012 Michael Ossmann
*
* 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 __RFFC5071_REGS_DEF
#define __RFFC5071_REGS_DEF
#define RFFC5071_REG_SET_CLEAN(_d, _r) (_d->regs_dirty &= ~(1UL<<_r))
#define RFFC5071_REG_SET_DIRTY(_d, _r) (_d->regs_dirty |= (1UL<<_r))
#define RFFC5071_READBACK_REG 31
/* Generate static inline accessors that operate on the global
* regs. Done this way to (1) allow defs to be scraped out and used
* elsewhere, e.g. in scripts, (2) to avoid dealing with endian
* (structs). This may be used in firmware, or on host predefined
* register loads. */
/* On set_, register is always set dirty, even if nothing
* changed. This makes sure that writes that have side effects,
* e.g. frequency setting, are not skipped. */
/* n=name, r=regnum, o=offset (bits from LSB) of LSB of field,
* l=length (bits) */
#define __MREG__(n,r,o,l) \
static inline uint16_t get_##n(rffc5071_driver_t* const _d) { \
return (_d->regs[r] >> o) & ((1L<<l)-1); \
} \
static inline void set_##n(rffc5071_driver_t* const _d, uint16_t v) { \
_d->regs[r] &= (uint16_t)(~(((1L<<l)-1)<<o)); \
_d->regs[r] |= (uint16_t)(((v&((1L<<l)-1))<<o)); \
RFFC5071_REG_SET_DIRTY(_d, r); \
}
/* REG 00 (0): LF */
__MREG__(RFFC5071_PLLCPL,0,0,3)
__MREG__(RFFC5071_P1CPDEF,0,3,6)
__MREG__(RFFC5071_P2CPDEF,0,9,6)
__MREG__(RFFC5071_IFACT,0,15,1)
#define RFFC5071_
/* REG 01 (1): XO */
__MREG__(RFFC5071_SUWAIT,1,0,10)
__MREG__(RFFC5071_XOCF,1,10,1)
__MREG__(RFFC5071_XOC,1,11,4)
__MREG__(RFFC5071_XOCH,1,15,1)
/* REG 02 (2): CAL_TIME */
__MREG__(RFFC5071_TKV2,2,0,4)
__MREG__(RFFC5071_TKV1,2,4,4)
__MREG__(RFFC5071_TCT,2,10,5)
__MREG__(RFFC5071_WAIT,2,15,1)
/* REG 03 (3): VCO_CTRL */
__MREG__(RFFC5071_ICPUP,3,1,2)
__MREG__(RFFC5071_REFST,3,3,1)
__MREG__(RFFC5071_XOI3,3,4,1)
__MREG__(RFFC5071_XOI2,3,5,1)
__MREG__(RFFC5071_XOI1,3,6,1)
__MREG__(RFFC5071_KVPOL,3,7,1)
__MREG__(RFFC5071_KVRNG,3,8,1)
__MREG__(RFFC5071_KVAVG,3,9,2)
__MREG__(RFFC5071_CLKPL,3,1,1)
__MREG__(RFFC5071_CTPOL,3,12,1)
__MREG__(RFFC5071_CTAVG,3,13,2)
__MREG__(RFFC5071_XTVCO,3,15,1)
/* REG 04 (4): CT_CAL1 */
__MREG__(RFFC5071_P1CTDEF,4,0,7)
__MREG__(RFFC5071_P1CT,4,7,1)
__MREG__(RFFC5071_P1CTV,4,8,5)
__MREG__(RFFC5071_P1CTGAIN,4,13,3)
/* REG 05 (5): CT_CAL2 */
__MREG__(RFFC5071_P2CTDEF,5,0,7)
__MREG__(RFFC5071_P2CT,5,7,1)
__MREG__(RFFC5071_P2CTV,5,8,5)
__MREG__(RFFC5071_P2CTGAIN,5,13,3)
/* REG 06 (6): PLL_CAL1 */
__MREG__(RFFC5071_P1SGN,6,2,1)
__MREG__(RFFC5071_P1KVGAIN,6,3,3)
__MREG__(RFFC5071_P1DN,6,6,9)
__MREG__(RFFC5071_P1KV,6,15,1)
/* REG 07 (7): PLL_CAL2 */
__MREG__(RFFC5071_P2SGN,7,2,1)
__MREG__(RFFC5071_P2KVGAIN,7,3,3)
__MREG__(RFFC5071_P2DB,7,6,9)
__MREG__(RFFC5071_P2KV,7,15,1)
/* REG 08 (8): VCO_AUTO */
__MREG__(RFFC5071_CTMIN,8,1,7)
__MREG__(RFFC5071_CTMAX,8,8,7)
__MREG__(RFFC5071_AUTO,8,15,1)
/* REG 09 (9): PLL_CTRL */
__MREG__(RFFC5071_PLLDY,9,0,2)
__MREG__(RFFC5071_ALOI,9,2,1)
__MREG__(RFFC5071_RELOK,9,3,1)
__MREG__(RFFC5071_LDLEV,9,4,1)
__MREG__(RFFC5071_LDEN,9,5,1)
__MREG__(RFFC5071_TVCO,9,6,5)
__MREG__(RFFC5071_PLLST,9,11,1)
__MREG__(RFFC5071_CLKDIV,9,12,3)
__MREG__(RFFC5071_DIVBY,9,15,1)
/* REG 0A (10): PLL_BIAS */
__MREG__(RFFC5071_P2VCOI,10,0,3)
__MREG__(RFFC5071_P2LOI,10,3,4)
__MREG__(RFFC5071_P1VCOI,10,8,3)
__MREG__(RFFC5071_P1LOI,10,11,4)
/* REG 0B (11): MIX_CONT */
__MREG__(RFFC5071_P2MIXIDD,11,9,3)
__MREG__(RFFC5071_P1MIXIDD,11,12,3)
__MREG__(RFFC5071_FULLD,11,15,1)
/* REG 0C (12): P1_FREQ1 */
__MREG__(RFFC5071_P1VCOSEL,12,0,2)
__MREG__(RFFC5071_P1PRESC,12,2,2)
__MREG__(RFFC5071_P1LODIV,12,4,3)
__MREG__(RFFC5071_P1N,12,7,9)
/* REG 0D (13): P1_FREQ2 */ /* !!!!! CHECK FOR OVERFLOW !!!!! */
__MREG__(RFFC5071_P1NMSB,13,0,16)
/* REG 0E (14): P1_FREQ3 */
__MREG__(RFFC5071_P1NLSB,14,8,8)
/* REG 0F (15): P2_FREQ1 */
__MREG__(RFFC5071_P2VCOSEL,15,0,2)
__MREG__(RFFC5071_P2PRESC,15,2,2)
__MREG__(RFFC5071_P2LODIV,15,4,3)
__MREG__(RFFC5071_P2N,15,7,9)
/* REG 10 (16): P2_FREQ2 */ /* !!!!! CHECK FOR OVERFLOW !!!!! */
__MREG__(RFFC5071_P2NMSB,16,0,16)
/* REG 11 (17): P2_FREQ3 */
__MREG__(RFFC5071_P2NLSB,17,8,8)
/* REG 12 (18): FN_CTRL */
__MREG__(RFFC5071_TZPS,18,1,1)
__MREG__(RFFC5071_DMODE,18,2,1)
__MREG__(RFFC5071_FM,18,3,1)
__MREG__(RFFC5071_DITH,18,4,1)
__MREG__(RFFC5071_DSM_MODE,18,5,1)
__MREG__(RFFC5071_PHSALNDLY,18,6,2)
__MREG__(RFFC5071_PHSALNGAIN,18,8,3)
__MREG__(RFFC5071_PHALN,18,11,1)
__MREG__(RFFC5071_SDM,18,12,2)
__MREG__(RFFC5071_DITHR,18,14,1)
__MREG__(RFFC5071_FNZ,18,15,1)
/* REG 13 (19): EXT_MOD */
__MREG__(RFFC5071_MODSTEP,19,10,4)
__MREG__(RFFC5071_MODSETUP,19,14,2)
/* REG 14 (20): FMOD */ /* !!!!! CHECK FOR OVERFLOW !!!!! */
__MREG__(RFFC5071_MODULATION,20,0,16)
/* REG 15 (21): SDI_CTRL */
__MREG__(RFFC5071_RESET,21,1,1)
__MREG__(RFFC5071_ADDR,21,11,1)
__MREG__(RFFC5071_4WIRE,21,12,1)
__MREG__(RFFC5071_MODE,21,13,1)
__MREG__(RFFC5071_ENBL,21,14,1)
__MREG__(RFFC5071_SIPIN,21,15,1)
/* REG 16 (22): GPO */
__MREG__(RFFC5071_LOCK,22,0,1)
__MREG__(RFFC5071_GATE,22,1,1)
__MREG__(RFFC5071_P1GPO,22,2,7)
__MREG__(RFFC5071_P2GPO,22,9,7)
/* REG 17 (23): T_VCO */
__MREG__(RFFC5071_CURVE_VCO3,23,7,3)
__MREG__(RFFC5071_CURVE_VCO2,23,10,3)
__MREG__(RFFC5071_CURVE_VCO1,23,13,3)
/* REG 18 (24): IQMOD1 */
__MREG__(RFFC5071_BUFDC,24,0,2)
__MREG__(RFFC5071_DIVBIAS,24,2,1)
__MREG__(RFFC5071_CALBLK,24,3,1)
__MREG__(RFFC5071_CALNUL,24,4,1)
__MREG__(RFFC5071_CALON,24,5,1)
__MREG__(RFFC5071_LOBIAS,24,6,2)
__MREG__(RFFC5071_MODBIAS,24,8,3)
__MREG__(RFFC5071_CTRL,24,11,5) /* shown as 5 fields in reg overview */
/* REG 19 (25): IQMOD2 */
__MREG__(RFFC5071_MODBUF,25,0,2)
__MREG__(RFFC5071_MOD,25,2,2)
__MREG__(RFFC5071_CALATTEN,25,4,2)
__MREG__(RFFC5071_RCTUNE,25,6,6)
__MREG__(RFFC5071_BBATTEN,25,12,4)
/* REG 1A (26): IQMOD3 */
__MREG__(RFFC5071_DACEN,26,3,1)
__MREG__(RFFC5071_BUFDACQ,26,4,6)
__MREG__(RFFC5071_BUFDACI,26,10,6)
/* REG 1B (27): IQMOD4 */
__MREG__(RFFC5071_BUFBIAS2,27,2,2)
__MREG__(RFFC5071_BUFBIAS1,27,4,2)
__MREG__(RFFC5071_MODDACQ,27,6,6)
__MREG__(RFFC5071_MODDACI,27,12,6)
/* REG 1C (28): T_CTRL */
__MREG__(RFFC5071_V_TEST,28,5,1)
__MREG__(RFFC5071_LDO_BY,28,6,1)
__MREG__(RFFC5071_EXT_FILT,28,7,1)
__MREG__(RFFC5071_REF_SEL,28,8,1)
__MREG__(RFFC5071_FILT_CTRL,28,9,2)
__MREG__(RFFC5071_FC_EN,28,11,1)
__MREG__(RFFC5071_TBL_SEL,28,12,2)
__MREG__(RFFC5071_TC_EN,28,14,2)
/* REG 1D (29): DEV_CTRL */
__MREG__(RFFC5071_BYPAS,29,1,1)
__MREG__(RFFC5071_CTCLK,29,2,1)
__MREG__(RFFC5071_DAC,29,3,1)
__MREG__(RFFC5071_CPD,29,4,1)
__MREG__(RFFC5071_CPU,29,5,1)
__MREG__(RFFC5071_RSMSTOPST,29,6,5)
__MREG__(RFFC5071_RSMST,29,11,1)
__MREG__(RFFC5071_READSEL,29,12,4)
/* REG 1E (30): TEST */
__MREG__(RFFC5071_LFSRD,30,0,1) /* n/a in reg overview */
__MREG__(RFFC5071_RCBYP,30,1,1)
__MREG__(RFFC5071_RGBYP,30,2,1)
__MREG__(RFFC5071_LFSRT,30,3,1)
__MREG__(RFFC5071_LFSRGATET,30,4,4)
__MREG__(RFFC5071_LFSRP,30,8,1)
__MREG__(RFFC5071_LFSR,30,9,1)
__MREG__(RFFC5071_TSEL,30,10,2)
__MREG__(RFFC5071_TMUX,30,12,3)
__MREG__(RFFC5071_TEN,30,15,1)
#endif // __RFFC5071_REGS_DEF

View File

@ -0,0 +1,184 @@
/*
* Copyright 2012 Michael Ossmann
* Copyright 2014 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h"
#include "rffc5071_spi.h"
static void rffc5071_spi_target_select(spi_bus_t* const bus) {
const rffc5071_spi_config_t* const config = bus->config;
gpio_clear(config->gpio_select);
}
static void rffc5071_spi_target_unselect(spi_bus_t* const bus) {
const rffc5071_spi_config_t* const config = bus->config;
gpio_set(config->gpio_select);
}
static void rffc5071_spi_direction_out(spi_bus_t* const bus) {
const rffc5071_spi_config_t* const config = bus->config;
gpio_output(config->gpio_data);
}
static void rffc5071_spi_direction_in(spi_bus_t* const bus) {
const rffc5071_spi_config_t* const config = bus->config;
gpio_input(config->gpio_data);
}
static void rffc5071_spi_data_out(spi_bus_t* const bus, const bool bit) {
const rffc5071_spi_config_t* const config = bus->config;
gpio_write(config->gpio_data, bit);
}
static bool rffc5071_spi_data_in(spi_bus_t* const bus) {
const rffc5071_spi_config_t* const config = bus->config;
return gpio_read(config->gpio_data);
}
static void rffc5071_spi_bus_init(spi_bus_t* const bus) {
const rffc5071_spi_config_t* const config = bus->config;
scu_pinmux(SCU_MIXER_SCLK, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_MIXER_SDATA, SCU_GPIO_FAST);
gpio_output(config->gpio_clock);
rffc5071_spi_direction_out(bus);
gpio_clear(config->gpio_clock);
gpio_clear(config->gpio_data);
}
static void rffc5071_spi_target_init(spi_bus_t* const bus) {
const rffc5071_spi_config_t* const config = bus->config;
/* Configure GPIO pins. */
scu_pinmux(SCU_MIXER_ENX, SCU_GPIO_FAST);
scu_pinmux(SCU_MIXER_RESETX, SCU_GPIO_FAST);
/* Set GPIO pins as outputs. */
gpio_output(config->gpio_select);
/* set to known state */
rffc5071_spi_target_unselect(bus);
}
void rffc5071_spi_start(spi_bus_t* const bus, const void* const config) {
bus->config = config;
rffc5071_spi_bus_init(bus);
rffc5071_spi_target_init(bus);
}
void rffc5071_spi_stop(spi_bus_t* const bus) {
(void)bus;
}
static void rffc5071_spi_serial_delay(spi_bus_t* const bus) {
(void)bus;
__asm__("nop");
}
static void rffc5071_spi_sck(spi_bus_t* const bus) {
const rffc5071_spi_config_t* const config = bus->config;
rffc5071_spi_serial_delay(bus);
gpio_set(config->gpio_clock);
rffc5071_spi_serial_delay(bus);
gpio_clear(config->gpio_clock);
}
static uint32_t rffc5071_spi_exchange_bit(spi_bus_t* const bus, const uint32_t bit) {
rffc5071_spi_data_out(bus, bit);
rffc5071_spi_sck(bus);
return rffc5071_spi_data_in(bus) ? 1 : 0;
}
static uint32_t rffc5071_spi_exchange_word(spi_bus_t* const bus, const uint32_t data, const size_t count) {
size_t bits = count;
const uint32_t msb = 1UL << (count - 1);
uint32_t t = data;
while (bits--) {
t = (t << 1) | rffc5071_spi_exchange_bit(bus, t & msb);
}
return t & ((1UL << count) - 1);
}
/* SPI register read.
*
* Send 9 bits:
* first bit is ignored,
* second bit is one for read operation,
* next 7 bits are register address.
* Then receive 16 bits (register value).
*/
/* SPI register write
*
* Send 25 bits:
* first bit is ignored,
* second bit is zero for write operation,
* next 7 bits are register address,
* next 16 bits are register value.
*/
void rffc5071_spi_transfer(spi_bus_t* const bus, void* const _data, const size_t count) {
if( count != 2 ) {
return;
}
uint16_t* const data = _data;
const bool direction_read = (data[0] >> 7) & 1;
/*
* The device requires two clocks while ENX is high before a serial
* transaction. This is not clearly documented.
*/
rffc5071_spi_sck(bus);
rffc5071_spi_sck(bus);
rffc5071_spi_target_select(bus);
data[0] = rffc5071_spi_exchange_word(bus, data[0], 9);
if( direction_read ) {
rffc5071_spi_direction_in(bus);
rffc5071_spi_sck(bus);
}
data[1] = rffc5071_spi_exchange_word(bus, data[1], 16);
rffc5071_spi_serial_delay(bus);
rffc5071_spi_target_unselect(bus);
rffc5071_spi_direction_out(bus);
/*
* The device requires a clock while ENX is high after a serial
* transaction. This is not clearly documented.
*/
rffc5071_spi_sck(bus);
}
void rffc5071_spi_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfer, const size_t count) {
if( count == 1 ) {
rffc5071_spi_transfer(bus, transfer[0].data, transfer[0].count);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2012 Michael Ossmann
* Copyright 2014 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 __RFFC5071_SPI_H
#define __RFFC5071_SPI_H
#include "spi_bus.h"
#include "gpio.h"
typedef struct rffc5071_spi_config_t {
gpio_t gpio_select;
gpio_t gpio_clock;
gpio_t gpio_data;
} rffc5071_spi_config_t;
void rffc5071_spi_start(spi_bus_t* const bus, const void* const config);
void rffc5071_spi_stop(spi_bus_t* const bus);
void rffc5071_spi_transfer(spi_bus_t* const bus, void* const data, const size_t count);
void rffc5071_spi_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfer, const size_t count);
#endif // __RFFC5071_SPI_H

View File

@ -0,0 +1,106 @@
/*
* 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.
*/
#include "hackrf_core.h"
#include <stdint.h>
#include "rom_iap.h"
#include "w25q80bv.h"
#define ROM_IAP_ADDR (0x10400100)
#define ROM_IAP_UNDEF_ADDR (0x12345678)
#define ROM_OTP_PART_ID_ADDR (0x40045000)
typedef void (* IAP_t)(uint32_t [],uint32_t[]);
typedef struct {
const IAP_t IAP; /* If equal to 0x12345678 IAP not implemented */
/* Other TBD */
} *pENTRY_ROM_API_t;
#define pROM_API ((pENTRY_ROM_API_t)ROM_IAP_ADDR)
/*
See Errata sheet ES_LPC43X0_A.pdf (LPC4350/30/20/10 Rev A)
3.5 IAP.1: In-Application Programming API not present on flashless parts
Introduction:
The LPC43x0 microcontrollers contain an APIfor In-Application Programming of flash
memory. This API also allows identification of the part.
Problem:
On the LPC43x0 microcontrollers, the IAP API is not present. The ISP interface is present
which allows the part to be identified externally (via the UART) but part identification is not
possible internally using the IAP call because it is not implemented.
The first word of the Part ID can be read directly from OTP at 0x40045000. The second word of the Part ID is always
'0' on flashless parts. */
bool iap_is_implemented(void)
{
bool res;
if( *((uint32_t*)ROM_IAP_ADDR) != ROM_IAP_UNDEF_ADDR )
{
res = true;
}else
{
res = false;
}
return res;
}
isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res)
{
uint32_t* p_u32_data;
if( iap_is_implemented() )
{
pROM_API->IAP( (uint32_t*)&iap_cmd_res->cmd_param, (uint32_t*)&iap_cmd_res->status_res);
}else
{
/*
Alternative way to retrieve Part Id on MCU with no IAP
Read Serial No => Read Unique ID in SPIFI (only compatible with W25Q80BV
*/
spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv);
w25q80bv_setup(&spi_flash);
switch(iap_cmd_res->cmd_param.command_code)
{
case IAP_CMD_READ_PART_ID_NO:
p_u32_data = (uint32_t*)ROM_OTP_PART_ID_ADDR;
iap_cmd_res->status_res.iap_result[0] = p_u32_data[0];
iap_cmd_res->status_res.iap_result[1] = p_u32_data[1];
iap_cmd_res->status_res.status_ret = CMD_SUCCESS;
break;
case IAP_CMD_READ_SERIAL_NO:
/* Only 64bits used */
iap_cmd_res->status_res.iap_result[0] = 0;
iap_cmd_res->status_res.iap_result[1] = 0;
w25q80bv_get_unique_id(&spi_flash, (w25q80bv_unique_id_t*)&iap_cmd_res->status_res.iap_result[2] );
iap_cmd_res->status_res.status_ret = CMD_SUCCESS;
break;
default:
iap_cmd_res->status_res.status_ret = ERROR_IAP_NOT_IMPLEMENTED;
break;
}
}
return iap_cmd_res->status_res.status_ret;
}

View File

@ -0,0 +1,121 @@
/*
* 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.
*/
#ifndef __ROM_IAP__
#define __ROM_IAP__
#include <stdint.h>
typedef enum
{
/* TODO define other commands */
IAP_CMD_INIT_IAP = 49,
/* Command Init IAP
Input Command code: 49 (decimal)
Return Code CMD_SUCCESS
Result None
Description Initializes and prepares the flash for erase and write operations.
Stack usage 88 B */
IAP_CMD_READ_PART_ID_NO = 54,
/* Read part identification number
Command Read part identification number
Input Command code: 54 (decimal)
Parameters:None
Return Code CMD_SUCCESS |
Result Result0:Part Identification Number.
Result1:Part Identification Number.
Description This command is used to read the part identification number. See Table 1082
<09>LPC43xx part identification numbers<72>.
The command returns two words: word0 followed by word1. Word 0 corresponds
to the part id and word1 indicates the flash configuration or contains 0x0 for
flashless parts.
Stack usage 8 B */
IAP_CMD_READ_SERIAL_NO = 58
/* Read device serial number
Input Command code: 58 (decimal)
Parameters: None
Return Code CMD_SUCCESS
Result Result0:First 32-bit word of Device Identification Number (at the lowest address)
Result1:Second 32-bit word of Device Identification Number
Result2:Third 32-bit word of Device Identification Number
Result3:Fourth 32-bit word of Device Identification Number
Description This command is used to read the device identification number. The serial number
may be used to uniquely identify a single unit among all LPC43xx devices.
Stack usage 8 B */
} iap_cmd_code_t;
/* ISP/IAP Return Code */
typedef enum
{
CMD_SUCCESS = 0x00000000, /* CMD_SUCCESS Command is executed successfully. Sent by ISP handler only when command given by the host has been completely and successfully executed. */
INVALID_COMMAND = 0x00000001, /* Invalid command. */
SRC_ADDR_ERROR = 0x00000002, /* Source address is not on word boundary. */
DST_ADDR_ERROR = 0x00000003, /* Destination address not on word or 256 byte boundary. */
SRC_ADDR_NOT_MAPPED = 0x00000004, /* Source address is not mapped in the memory map. Count value is taken into consideration where applicable. */
DST_ADDR_NOT_MAPPED = 0x00000005, /* Destination address is not mapped in the memory map. Count value is taken into consideration where applicable.*/
COUNT_ERROR = 0x00000006, /* Byte count is not multiple of 4 or is not a permitted value. */
INVALID_SECTOR = 0x00000007, /* Sector number is invalid or end sector number is greater than start sector number. */
SECTOR_NOT_BLANK = 0x00000008, /* Sector is not blank. */
SECTOR_NOT_PREP_WRITE_OP = 0x00000009, /* Command to prepare sector for write operation was not executed. */
COMPARE_ERROR = 0x0000000A, /* Source and destination data not equal. */
BUSY = 0x0000000B, /* Flash programming hardware interface is busy. */
PARAM_ERROR = 0x0000000C, /* Insufficient number of parameters or invalid parameter. */
ADDR_ERROR = 0x0000000D, /* Address is not on word boundary. */
ADDR_NOT_MAPPED = 0x0000000E, /* Address is not mapped in the memory map. Count value is taken in to consideration where applicable. */
CMD_LOCKED = 0x0000000F, /* Command is locked. */
INVALID_CODE = 0x00000010, /* Unlock code is invalid. */
INVALID_BAUD_RATE = 0x00000011, /* Invalid baud rate setting. */
INVALID_STOP_BIT = 0x00000012, /* Invalid stop bit setting. */
CODE_READ_PROTECTION_ENABLED = 0x00000013, /* Code read protection enabled. */
INVALID_FLASH_UNIT = 0x00000014, /* Invalid flash unit. */
USER_CODE_CHECKSUM = 0x00000015,
ERROR_SETTING_ACTIVE_PARTITION = 0x00000016,
/* Special Error */
ERROR_IAP_NOT_IMPLEMENTED = 0x00000100 /* IAP is not implemented in this part */
} isp_iap_ret_code_t;
typedef struct
{
/* Input Command/Param */
struct
{
iap_cmd_code_t command_code;
uint32_t iap_param[5];
} cmd_param;
/* Output Status/Result */
struct
{
isp_iap_ret_code_t status_ret;
uint32_t iap_result[4];
} status_res;
} iap_cmd_res_t;
/* Check if IAP is implemented */
bool iap_is_implemented(void);
isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res);
#endif//__ROM_IAP__

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,307 @@
/*
* Copyright 2012 Jared Boone <jared@sharebrained.com>
* Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
* Copyright 2017 Schuyler St. Leger <schuyler.st.leger@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.
*/
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/sgpio.h>
#include <hackrf_core.h>
#include <sgpio.h>
#ifdef RAD1O
static void update_q_invert(sgpio_config_t* const config);
#endif
void sgpio_configure_pin_functions(sgpio_config_t* const config) {
scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
scu_pinmux(SCU_PINMUX_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
scu_pinmux(SCU_PINMUX_SGPIO2, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
scu_pinmux(SCU_PINMUX_SGPIO3, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
scu_pinmux(SCU_PINMUX_SGPIO4, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
scu_pinmux(SCU_PINMUX_SGPIO5, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
scu_pinmux(SCU_PINMUX_SGPIO6, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_SGPIO7, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
scu_pinmux(SCU_PINMUX_SGPIO8, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
scu_pinmux(SCU_PINMUX_SGPIO9, SCU_GPIO_FAST | SCU_CONF_FUNCTION7);
scu_pinmux(SCU_PINMUX_SGPIO10, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
scu_pinmux(SCU_PINMUX_SGPIO11, SCU_GPIO_FAST | SCU_CONF_FUNCTION6);
scu_pinmux(SCU_PINMUX_SGPIO12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); /* GPIO0[13] */
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_q_invert(config, 0);
hw_sync_enable(0);
gpio_output(config->gpio_rx_q_invert);
gpio_output(config->gpio_hw_sync_enable);
}
void sgpio_set_slice_mode(
sgpio_config_t* const config,
const bool multi_slice
) {
config->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)
ADC=> CLK x 2=CLKx2 with CLKx2(0)rising=D0Q, CLKx2(1)rising=D1I (corresponds to CLK(0)falling+tD0Q=>D0Q, CLK(1)rising+tDOI=>D1I, CLK(1)falling+tD0Q=>D1Q, CLK(1)rising+tDOI=>D2I ...)
tDOI(CLK Rise to I-ADC Channel-I Output Data Valid)=7.4 to 9ns, tD0Q(CLK Fall to Q-ADC Channel-Q Output Data Valid)=6.9 to 9ns
DAC=> CLK x 2=CLKx2 with CLKx2(0)rising=Q:N-2, CLKx2(1)rising=I:N-1(corresponds to CLK(0)rising=>Q:N-2, CLK(0)falling I:N-1, CLK(1)rising=>Q:N-1, CLK(1)falling I:N ...)
tDSI(I-DAC Data to CLK Fall Setup Time)=min 10ns, tDSQ(Q-DAC Data to CLK Rise Setup Time)=min 10ns
SGPIO8 Clock Input (External Clock)
SGPIO9 Capture Input (Capture/ChipSelect, 1=Enable Capture, 0=Disable capture)
SGPIO10 Disable Output (1/High=Disable codec data stream, 0/Low=Enable codec data stream)
SGPIO11 Direction Output (1/High=TX mode LPC43xx=>CPLD=>DAC, 0/Low=RX mode LPC43xx<=CPLD<=ADC)
*/
void sgpio_configure(
sgpio_config_t* const config,
const sgpio_direction_t direction
) {
// Disable all counters during configuration
SGPIO_CTRL_ENABLE = 0;
// Set SGPIO output values.
const uint_fast8_t cpld_direction =
(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)
;
#ifdef RAD1O
/* The data direction might have changed. Check if we need to
* adjust the q inversion. */
update_q_invert(config);
#endif
// Enable SGPIO pin outputs.
const uint_fast16_t sgpio_gpio_data_direction =
(direction == SGPIO_DIRECTION_TX)
? (0xFF << 0)
: (0x00 << 0);
SGPIO_GPIO_OENREG =
(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)
| sgpio_gpio_data_direction // 0xFF=Output all SGPIO High(TX mode), 0x00=Output all SPGIO Low(RX mode)
;
SGPIO_OUT_MUX_CFG( 8) = // SGPIO8: Input: clock
SGPIO_OUT_MUX_CFG_P_OE_CFG(0) /* 0x0 gpio_oe (state set by GPIO_OEREG) */
| SGPIO_OUT_MUX_CFG_P_OUT_CFG(0) /* 0x0 dout_doutm1 (1-bit mode) */
;
SGPIO_OUT_MUX_CFG( 9) = // SGPIO9: Input: qualifier
SGPIO_OUT_MUX_CFG_P_OE_CFG(0) /* 0x0 gpio_oe (state set by GPIO_OEREG) */
| SGPIO_OUT_MUX_CFG_P_OUT_CFG(0) /* 0x0 dout_doutm1 (1-bit mode) */
;
SGPIO_OUT_MUX_CFG(10) = // GPIO10: Output: disable
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(11) = // GPIO11: Output: direction
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 =
config->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".
SGPIO_OUT_MUX_CFG(i) =
SGPIO_OUT_MUX_CFG_P_OE_CFG(0)
| SGPIO_OUT_MUX_CFG_P_OUT_CFG(output_multiplexing_mode) /* 11/0xB=dout_doutm8c (8-bit mode 8c)(multislice L0/7, N0/7), 9=dout_doutm8a (8-bit mode 8a)(A0/7,B0/7) */
;
}
const uint_fast8_t slice_indices[] = {
SGPIO_SLICE_A,
SGPIO_SLICE_I,
SGPIO_SLICE_E,
SGPIO_SLICE_J,
SGPIO_SLICE_C,
SGPIO_SLICE_K,
SGPIO_SLICE_F,
SGPIO_SLICE_L,
};
const uint_fast8_t slice_gpdma = SGPIO_SLICE_H;
const uint_fast8_t pos = config->slice_mode_multislice ? 0x1f : 0x03;
const bool single_slice = !config->slice_mode_multislice;
const uint_fast8_t slice_count = config->slice_mode_multislice ? 8 : 1;
const uint_fast8_t clk_capture_mode = (direction == SGPIO_DIRECTION_TX) ? 0 : 0;
// Also enable slice D for clkout to the SCTimer
uint32_t slice_enable_mask = BIT3;
/* 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) && (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 */
SGPIO_MUX_CFG(slice_index) =
SGPIO_MUX_CFG_CONCAT_ORDER(concat_order)
| SGPIO_MUX_CFG_CONCAT_ENABLE(concat_enable)
| 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_index) =
SGPIO_SLICE_MUX_CFG_INV_QUALIFIER(0) /* 0x0=Use normal qualifier. */
| SGPIO_SLICE_MUX_CFG_PARALLEL_MODE(3) /* 0x3=Shift 1 byte(8bits) 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_index) = 0; // External clock, don't care
SGPIO_COUNT(slice_index) = 0; // External clock, don't care
SGPIO_POS(slice_index) =
SGPIO_POS_POS_RESET(pos)
| SGPIO_POS_POS(pos)
;
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( config->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;
}
void sgpio_cpld_stream_enable(sgpio_config_t* const config) {
(void)config;
// Enable codec data stream.
SGPIO_GPIO_OUTREG &= ~(1L << 10); /* SGPIO10 */
}
void sgpio_cpld_stream_disable(sgpio_config_t* const config) {
(void)config;
// Disable codec data stream.
SGPIO_GPIO_OUTREG |= (1L << 10); /* SGPIO10 */
}
bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config) {
(void)config;
return (SGPIO_GPIO_OUTREG & (1L << 10)) == 0; /* SGPIO10 */
}
#ifdef RAD1O
/* The rad1o hardware has a bug which makes it
* necessary to also switch between the two options based
* on TX or RX mode.
*
* We use the state of the pin to determine which way we
* have to go.
*
* As TX/RX can change without sgpio_cpld_stream_rx_set_q_invert
* being called, we store a local copy of its parameter. */
static bool sgpio_invert = false;
/* Called when TX/RX changes od sgpio_cpld_stream_rx_set_q_invert
* gets called. */
static void update_q_invert(sgpio_config_t* const config) {
/* 1=Output SGPIO11 High(TX mode), 0=Output SGPIO11 Low(RX mode) */
bool tx_mode = (SGPIO_GPIO_OUTREG & (1 << 11)) > 0;
/* 0.13: P1_18 */
if( !sgpio_invert & !tx_mode) {
gpio_write(config->gpio_rx_q_invert, 1);
} else if( !sgpio_invert & tx_mode) {
gpio_write(config->gpio_rx_q_invert, 0);
} else if( sgpio_invert & !tx_mode) {
gpio_write(config->gpio_rx_q_invert, 0);
} else if( sgpio_invert & tx_mode) {
gpio_write(config->gpio_rx_q_invert, 1);
}
}
void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, const uint_fast8_t invert) {
if( invert ) {
sgpio_invert = true;
} else {
sgpio_invert = false;
}
update_q_invert(config);
}
#else
void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, const uint_fast8_t invert) {
gpio_write(config->gpio_rx_q_invert, invert);
}
#endif

View File

@ -0,0 +1,59 @@
/*
* Copyright 2012 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SGPIO_H__
#define __SGPIO_H__
#include <stdint.h>
#include <stdbool.h>
#include <libopencm3/lpc43xx/sgpio.h>
#include "gpio.h"
typedef enum {
SGPIO_DIRECTION_RX,
SGPIO_DIRECTION_TX,
} sgpio_direction_t;
typedef struct sgpio_config_t {
gpio_t gpio_rx_q_invert;
gpio_t gpio_hw_sync_enable;
bool slice_mode_multislice;
} sgpio_config_t;
void sgpio_configure_pin_functions(sgpio_config_t* const config);
void sgpio_test_interface(sgpio_config_t* const config);
void sgpio_set_slice_mode(
sgpio_config_t* const config,
const bool multi_slice
);
void sgpio_configure(
sgpio_config_t* const config,
const sgpio_direction_t direction
);
void sgpio_cpld_stream_enable(sgpio_config_t* const config);
void sgpio_cpld_stream_disable(sgpio_config_t* const config);
bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config);
void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, const uint_fast8_t invert);
#endif//__SGPIO_H__

View File

@ -0,0 +1,291 @@
/*
* 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.
*/
#include "si5351c.h"
enum pll_sources active_clock_source = PLL_SOURCE_UNINITIALIZED;
/* External clock output default is deactivated as it creates noise */
uint8_t clk3_ctrl = SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE;
/* write to single register */
void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val)
{
const uint8_t data_tx[] = { reg, val };
si5351c_write(drv, data_tx, 2);
}
/* read single register */
uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg)
{
const uint8_t data_tx[] = { reg };
uint8_t data_rx[] = { 0x00 };
i2c_bus_transfer(drv->bus, drv->i2c_address, data_tx, 1, data_rx, 1);
return data_rx[0];
}
/*
* Write to one or more contiguous registers. data[0] should be the first
* register number, one or more values follow.
*/
void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count)
{
i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0);
}
/* Disable all CLKx outputs. */
void si5351c_disable_all_outputs(si5351c_driver_t* const drv)
{
uint8_t data[] = { 3, 0xFF };
si5351c_write(drv, data, sizeof(data));
}
/* Turn off OEB pin control for all CLKx */
void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv)
{
uint8_t data[] = { 9, 0xFF };
si5351c_write(drv, data, sizeof(data));
}
/* Power down all CLKx */
void si5351c_power_down_all_clocks(si5351c_driver_t* const drv)
{
uint8_t data[] = { 16
, SI5351C_CLK_POWERDOWN
, SI5351C_CLK_POWERDOWN
, SI5351C_CLK_POWERDOWN
, SI5351C_CLK_POWERDOWN
, SI5351C_CLK_POWERDOWN
, SI5351C_CLK_POWERDOWN
, SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE
, SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE
};
si5351c_write(drv, data, sizeof(data));
}
/*
* Register 183: Crystal Internal Load Capacitance
* Reads as 0xE4 on power-up
* Set to 8pF based on crystal specs and HackRF One testing
*/
void si5351c_set_crystal_configuration(si5351c_driver_t* const drv)
{
uint8_t data[] = { 183, 0x80 };
si5351c_write(drv, data, sizeof(data));
}
/*
* Register 187: Fanout Enable
* Turn on XO and MultiSynth fanout only.
*/
void si5351c_enable_xo_and_ms_fanout(si5351c_driver_t* const drv)
{
uint8_t data[] = { 187, 0xD0 };
si5351c_write(drv, data, sizeof(data));
}
/*
* Register 15: PLL Input Source
* CLKIN_DIV=0 (Divide by 1)
* PLLA_SRC=0 (XTAL)
* PLLB_SRC=1 (CLKIN)
*/
void si5351c_configure_pll_sources(si5351c_driver_t* const drv)
{
uint8_t data[] = { 15, 0x08 };
si5351c_write(drv, data, sizeof(data));
}
/* MultiSynth NA (PLLA) and NB (PLLB) */
void si5351c_configure_pll_multisynth(si5351c_driver_t* const drv)
{
/*PLLA: 25MHz XTAL * (0x0e00+512)/128 = 800mhz -> int mode */
uint8_t data[] = { 26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00 };
si5351c_write(drv, data, sizeof(data));
/*PLLB: 10MHz CLKIN * (0x2600+512)/128 = 800mhz */
data[0] = 34;
data[4] = 0x26;
si5351c_write(drv, data, sizeof(data));
}
void si5351c_reset_pll(si5351c_driver_t* const drv)
{
/* reset PLLA and PLLB */
uint8_t data[] = { 177, 0xA0 };
si5351c_write(drv, data, sizeof(data));
}
void si5351c_configure_multisynth(si5351c_driver_t* const drv,
const uint_fast8_t ms_number,
const uint32_t p1, const uint32_t p2, const uint32_t p3,
const uint_fast8_t r_div)
{
/*
* TODO: Check for p3 > 0? 0 has no meaning in fractional mode?
* And it makes for more jitter in integer mode.
*/
/*
* r is the r divider value encoded:
* 0 means divide by 1
* 1 means divide by 2
* 2 means divide by 4
* ...
* 7 means divide by 128
*/
const uint_fast8_t register_number = 42 + (ms_number * 8);
uint8_t data[] = {
register_number,
(p3 >> 8) & 0xFF,
(p3 >> 0) & 0xFF,
(r_div << 4) | (0 << 2) | ((p1 >> 16) & 0x3),
(p1 >> 8) & 0xFF,
(p1 >> 0) & 0xFF,
(((p3 >> 16) & 0xF) << 4) | (((p2 >> 16) & 0xF) << 0),
(p2 >> 8) & 0xFF,
(p2 >> 0) & 0xFF };
si5351c_write(drv, data, sizeof(data));
}
void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll_sources source)
{
uint8_t pll;
#ifdef RAD1O
(void) source;
/* PLLA on XTAL */
pll = SI5351C_CLK_PLL_SRC_A;
#endif
#if (defined JAWBREAKER || defined HACKRF_ONE)
if (source == PLL_SOURCE_CLKIN) {
/* PLLB on CLKIN */
pll = SI5351C_CLK_PLL_SRC_B;
} else {
/* PLLA on XTAL */
pll = SI5351C_CLK_PLL_SRC_A;
}
#endif
/* Clock to CPU is deactivated as it is not used and creates noise */
/* External clock output is kept in current state */
uint8_t data[] = {16
,SI5351C_CLK_FRAC_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA)
,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA) | SI5351C_CLK_INV
,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_0_4) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_2MA)
,clk3_ctrl
,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_6MA) | SI5351C_CLK_INV
,SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | 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 /*not connected, but: plla int mode*/
};
si5351c_write(drv, data, sizeof(data));
}
#define SI5351C_CLK_ENABLE(x) (0<<x)
#define SI5351C_CLK_DISABLE(x) (1<<x)
#define SI5351C_REG_OUTPUT_EN (3)
#define SI5351C_REG_CLK3_CTRL (19)
void si5351c_enable_clock_outputs(si5351c_driver_t* const drv)
{
/* Enable CLK outputs 0, 1, 2, 4, 5 only. */
/* 7: Clock to CPU is deactivated as it is not used and creates noise */
/* 3: External clock output is deactivated by default */
// uint8_t data[] = { 3, ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5))};
uint8_t data[] = { SI5351C_REG_OUTPUT_EN,
SI5351C_CLK_ENABLE(0) |
SI5351C_CLK_ENABLE(1) |
SI5351C_CLK_ENABLE(2) |
SI5351C_CLK_DISABLE(3) |
SI5351C_CLK_ENABLE(4) |
SI5351C_CLK_ENABLE(5) |
SI5351C_CLK_DISABLE(6) |
SI5351C_CLK_DISABLE(7)
};
si5351c_write(drv, data, sizeof(data));
}
void si5351c_set_int_mode(si5351c_driver_t* const drv, const uint_fast8_t ms_number, const uint_fast8_t on){
uint8_t data[] = {16, 0};
if(ms_number < 8){
data[0] = 16 + ms_number;
data[1] = si5351c_read_single(drv, data[0]);
if(on)
data[1] |= SI5351C_CLK_INT_MODE;
else
data[1] &= ~(SI5351C_CLK_INT_MODE);
si5351c_write(drv, data, 2);
}
}
void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source)
{
if( source != active_clock_source ) {
si5351c_configure_clock_control(drv, source);
active_clock_source = source;
}
}
bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv) {
return (si5351c_read_single(drv, 0) & SI5351C_LOS) == 0;
}
void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable)
{
/* Set optput in output enable register */
uint8_t output_enable = si5351c_read_single(drv, 3);
output_enable = output_enable & !SI5351C_CLK_DISABLE(3);
if(enable)
output_enable = output_enable | SI5351C_CLK_ENABLE(3);
else
output_enable = output_enable | SI5351C_CLK_DISABLE(3);
uint8_t oe_data[] = {SI5351C_REG_OUTPUT_EN, output_enable};
si5351c_write(drv, oe_data, 2);
/* Configure clock to 10MHz (TODO customisable?) */
si5351c_configure_multisynth(drv, 3, 80*128-512, 0, 1, 0);
/* Set power up/doen in CLK3 control register*/
uint8_t pll;
#ifdef RAD1O
/* PLLA on XTAL */
pll = SI5351C_CLK_PLL_SRC_A;
#endif
#if (defined JAWBREAKER || defined HACKRF_ONE)
if (active_clock_source == PLL_SOURCE_CLKIN) {
/* PLLB on CLKIN */
pll = SI5351C_CLK_PLL_SRC_B;
} else {
/* PLLA on XTAL */
pll = SI5351C_CLK_PLL_SRC_A;
}
#endif
if(enable)
clk3_ctrl = SI5351C_CLK_INT_MODE | SI5351C_CLK_PLL_SRC(pll) | SI5351C_CLK_SRC(SI5351C_CLK_SRC_MULTISYNTH_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA);
else
clk3_ctrl = SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE;
uint8_t clk3_data[] = {SI5351C_REG_CLK3_CTRL, clk3_ctrl};
si5351c_write(drv, clk3_data, 2);
}

View File

@ -0,0 +1,100 @@
/*
* 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.
*/
#ifndef __SI5351C_H
#define __SI5351C_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#include <stdbool.h>
#include "i2c_bus.h"
#define SI_INTDIV(x) (x*128-512)
#define SI5351C_CLK_POWERDOWN (1<<7)
#define SI5351C_CLK_INT_MODE (1<<6)
#define SI5351C_CLK_FRAC_MODE (0<<6)
#define SI5351C_CLK_PLL_SRC(x) (x<<5)
#define SI5351C_CLK_PLL_SRC_A 0
#define SI5351C_CLK_PLL_SRC_B 1
#define SI5351C_CLK_INV (1<<4)
#define SI5351C_CLK_SRC(x) (x<<2)
#define SI5351C_CLK_SRC_XTAL 0
#define SI5351C_CLK_SRC_CLKIN 1
#define SI5351C_CLK_SRC_MULTISYNTH_0_4 2
#define SI5351C_CLK_SRC_MULTISYNTH_SELF 3
#define SI5351C_CLK_IDRV(x) (x<<0)
#define SI5351C_CLK_IDRV_2MA 0
#define SI5351C_CLK_IDRV_4MA 1
#define SI5351C_CLK_IDRV_6MA 2
#define SI5351C_CLK_IDRV_8MA 3
#define SI5351C_LOS (1<<4)
enum pll_sources {
PLL_SOURCE_UNINITIALIZED = -1,
PLL_SOURCE_XTAL = 0,
PLL_SOURCE_CLKIN = 1,
};
typedef struct {
i2c_bus_t* const bus;
uint8_t i2c_address;
} si5351c_driver_t;
void si5351c_disable_all_outputs(si5351c_driver_t* const drv);
void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv);
void si5351c_power_down_all_clocks(si5351c_driver_t* const drv);
void si5351c_set_crystal_configuration(si5351c_driver_t* const drv);
void si5351c_enable_xo_and_ms_fanout(si5351c_driver_t* const drv);
void si5351c_configure_pll_sources(si5351c_driver_t* const drv);
void si5351c_configure_pll_multisynth(si5351c_driver_t* const drv);
void si5351c_reset_pll(si5351c_driver_t* const drv);
void si5351c_configure_multisynth(si5351c_driver_t* const drv,
const uint_fast8_t ms_number,
const uint32_t p1, const uint32_t p2, const uint32_t p3,
const uint_fast8_t r_div);
void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll_sources source);
void si5351c_enable_clock_outputs(si5351c_driver_t* const drv);
void si5351c_set_int_mode(si5351c_driver_t* const drv, const uint_fast8_t ms_number, const uint_fast8_t on);
void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source);
bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv);
void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val);
uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg);
void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count);
void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable);
#ifdef __cplusplus
}
#endif
#endif /* __SI5351C_H */

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 "spi_bus.h"
void spi_bus_start(spi_bus_t* const bus, const void* const config) {
bus->start(bus, config);
}
void spi_bus_stop(spi_bus_t* const bus) {
bus->stop(bus);
}
void spi_bus_transfer(spi_bus_t* const bus, void* const data, const size_t count) {
bus->transfer(bus, data, count);
}
void spi_bus_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count) {
bus->transfer_gather(bus, transfers, count);
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 __SPI_BUS_H__
#define __SPI_BUS_H__
#include <stddef.h>
typedef struct {
void* const data;
const size_t count;
} spi_transfer_t;
struct spi_bus_t;
typedef struct spi_bus_t spi_bus_t;
struct spi_bus_t {
void* const obj;
const void* config;
void (*start)(spi_bus_t* const bus, const void* const config);
void (*stop)(spi_bus_t* const bus);
void (*transfer)(spi_bus_t* const bus, void* const data, const size_t count);
void (*transfer_gather)(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count);
};
void spi_bus_start(spi_bus_t* const bus, const void* const config);
void spi_bus_stop(spi_bus_t* const bus);
void spi_bus_transfer(spi_bus_t* const bus, void* const data, const size_t count);
void spi_bus_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count);
#endif/*__SPI_BUS_H__*/

View File

@ -0,0 +1,109 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 "spi_ssp.h"
#include <libopencm3/lpc43xx/rgu.h>
#include <libopencm3/lpc43xx/ssp.h>
void spi_ssp_start(spi_bus_t* const bus, const void* const _config) {
const ssp_config_t* const config = _config;
if( bus->obj == (void*)SSP0_BASE ) {
/* Reset SPIFI peripheral before to Erase/Write SPIFI memory through SPI */
RESET_CTRL1 = RESET_CTRL1_SPIFI_RST;
}
gpio_set(config->gpio_select);
gpio_output(config->gpio_select);
SSP_CR1(bus->obj) = 0;
SSP_CPSR(bus->obj) = config->clock_prescale_rate;
SSP_CR0(bus->obj) =
(config->serial_clock_rate << 8)
| SSP_CPOL_0_CPHA_0
| SSP_FRAME_SPI
| config->data_bits
;
SSP_CR1(bus->obj) =
SSP_SLAVE_OUT_ENABLE
| SSP_MASTER
| SSP_ENABLE
| SSP_MODE_NORMAL
;
bus->config = config;
}
void spi_ssp_stop(spi_bus_t* const bus) {
SSP_CR1(bus->obj) = 0;
}
static void spi_ssp_wait_for_tx_fifo_not_full(spi_bus_t* const bus) {
while( (SSP_SR(bus->obj) & SSP_SR_TNF) == 0 );
}
static void spi_ssp_wait_for_rx_fifo_not_empty(spi_bus_t* const bus) {
while( (SSP_SR(bus->obj) & SSP_SR_RNE) == 0 );
}
static void spi_ssp_wait_for_not_busy(spi_bus_t* const bus) {
while( SSP_SR(bus->obj) & SSP_SR_BSY );
}
static uint32_t spi_ssp_transfer_word(spi_bus_t* const bus, const uint32_t data) {
spi_ssp_wait_for_tx_fifo_not_full(bus);
SSP_DR(bus->obj) = data;
spi_ssp_wait_for_not_busy(bus);
spi_ssp_wait_for_rx_fifo_not_empty(bus);
return SSP_DR(bus->obj);
}
void spi_ssp_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count) {
const ssp_config_t* const config = bus->config;
const bool word_size_u16 = (SSP_CR0(bus->obj) & 0xf) > SSP_DATA_8BITS;
gpio_clear(config->gpio_select);
for(size_t i=0; i<count; i++) {
const size_t data_count = transfers[i].count;
if( word_size_u16 ) {
uint16_t* const data = transfers[i].data;
for(size_t j=0; j<data_count; j++) {
data[j] = spi_ssp_transfer_word(bus, data[j]);
}
} else {
uint8_t* const data = transfers[i].data;
for(size_t j=0; j<data_count; j++) {
data[j] = spi_ssp_transfer_word(bus, data[j]);
}
}
}
gpio_set(config->gpio_select);
}
void spi_ssp_transfer(spi_bus_t* const bus, void* const data, const size_t count) {
const spi_transfer_t transfers[] = {
{ data, count },
};
spi_ssp_transfer_gather(bus, transfers, 1);
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* 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 __SPI_SSP_H__
#define __SPI_SSP_H__
#include <stdint.h>
#include <stddef.h>
#include "spi_bus.h"
#include "gpio.h"
#include <libopencm3/lpc43xx/ssp.h>
typedef struct ssp_config_t {
ssp_datasize_t data_bits;
uint8_t serial_clock_rate;
uint8_t clock_prescale_rate;
gpio_t gpio_select;
} ssp_config_t;
void spi_ssp_start(spi_bus_t* const bus, const void* const config);
void spi_ssp_stop(spi_bus_t* const bus);
void spi_ssp_transfer(spi_bus_t* const bus, void* const data, const size_t count);
void spi_ssp_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count);
#endif/*__SPI_SSP_H__*/

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.
*/
#include <streaming.h>
#include <libopencm3/lpc43xx/m4/nvic.h>
#include <libopencm3/lpc43xx/sgpio.h>
void baseband_streaming_enable(sgpio_config_t* const sgpio_config) {
SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A);
sgpio_cpld_stream_enable(sgpio_config);
}
void baseband_streaming_disable(sgpio_config_t* const sgpio_config) {
sgpio_cpld_stream_disable(sgpio_config);
}

View File

@ -0,0 +1,31 @@
/*
* 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__
#include <sgpio.h>
void baseband_streaming_enable(sgpio_config_t* const sgpio_config);
void baseband_streaming_disable(sgpio_config_t* const sgpio_config);
#endif/*__STREAMING_H__*/

View File

@ -0,0 +1,154 @@
/*
* 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 "hackrf_ui.h"
#include <hackrf_core.h>
#include <mixer.h>
#include <max2837.h>
#include <sgpio.h>
#include <operacake.h>
#define FREQ_ONE_MHZ (1000*1000)
#define MIN_LP_FREQ_MHZ (0)
#define MAX_LP_FREQ_MHZ (2150)
#define MIN_BYPASS_FREQ_MHZ (2150)
#define MAX_BYPASS_FREQ_MHZ (2750)
#define MIN_HP_FREQ_MHZ (2750)
#define MID1_HP_FREQ_MHZ (3600)
#define MID2_HP_FREQ_MHZ (5100)
#define MAX_HP_FREQ_MHZ (7250)
#define MIN_LO_FREQ_HZ (84375000)
#define MAX_LO_FREQ_HZ (5400000000ULL)
static uint32_t max2837_freq_nominal_hz=2560000000;
uint64_t freq_cache = 100000000;
/*
* Set freq/tuning between 0MHz to 7250 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 mixer_freq_mhz;
uint32_t MAX2837_freq_hz;
uint64_t real_mixer_freq_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);
max2837_set_mode(&max2837, MAX2837_MODE_STANDBY);
if(freq_mhz < MAX_LP_FREQ_MHZ)
{
rf_path_set_filter(&rf_path, RF_PATH_FILTER_LOW_PASS);
#ifdef RAD1O
max2837_freq_nominal_hz = 2300000000;
#else
/* IF is graduated from 2650 MHz to 2343 MHz */
max2837_freq_nominal_hz = 2650000000 - (freq / 7);
#endif
mixer_freq_mhz = (max2837_freq_nominal_hz / FREQ_ONE_MHZ) + freq_mhz;
/* Set Freq and read real freq */
real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz);
max2837_set_frequency(&max2837, real_mixer_freq_hz - freq);
sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1);
}else if( (freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ) )
{
rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS);
MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz;
/* mixer_freq_mhz <= not used in Bypass mode */
max2837_set_frequency(&max2837, MAX2837_freq_hz);
sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0);
}else if( (freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ) )
{
if (freq_mhz < MID1_HP_FREQ_MHZ) {
/* IF is graduated from 2150 MHz to 2750 MHz */
max2837_freq_nominal_hz = 2150000000 + (((freq - 2750000000) * 60) / 85);
} else if (freq_mhz < MID2_HP_FREQ_MHZ) {
/* IF is graduated from 2350 MHz to 2650 MHz */
max2837_freq_nominal_hz = 2350000000 + ((freq - 3600000000) / 5);
} else {
/* IF is graduated from 2500 MHz to 2738 MHz */
max2837_freq_nominal_hz = 2500000000 + ((freq - 5100000000) / 9);
}
rf_path_set_filter(&rf_path, RF_PATH_FILTER_HIGH_PASS);
mixer_freq_mhz = freq_mhz - (max2837_freq_nominal_hz / FREQ_ONE_MHZ);
/* Set Freq and read real freq */
real_mixer_freq_hz = mixer_set_frequency(&mixer, mixer_freq_mhz);
max2837_set_frequency(&max2837, freq - real_mixer_freq_hz);
sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0);
}else
{
/* Error freq_mhz too high */
success = false;
}
max2837_set_mode(&max2837, prior_max2837_mode);
if( success ) {
freq_cache = freq;
hackrf_ui()->set_frequency(freq);
#ifdef HACKRF_ONE
operacake_set_range(freq_mhz);
#endif
}
return success;
}
bool set_freq_explicit(const uint64_t if_freq_hz, const uint64_t lo_freq_hz,
const rf_path_filter_t path)
{
if ((if_freq_hz < ((uint64_t)MIN_BYPASS_FREQ_MHZ * FREQ_ONE_MHZ))
|| (if_freq_hz > ((uint64_t)MAX_BYPASS_FREQ_MHZ * FREQ_ONE_MHZ))) {
return false;
}
if ((path != RF_PATH_FILTER_BYPASS) &&
((lo_freq_hz < MIN_LO_FREQ_HZ) || (lo_freq_hz > MAX_LO_FREQ_HZ))) {
return false;
}
if (path > 2) {
return false;
}
rf_path_set_filter(&rf_path, path);
max2837_set_frequency(&max2837, if_freq_hz);
if (lo_freq_hz > if_freq_hz) {
sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1);
} else {
sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0);
}
if (path != RF_PATH_FILTER_BYPASS) {
(void)mixer_set_frequency(&mixer, lo_freq_hz / FREQ_ONE_MHZ);
}
return true;
}

View File

@ -0,0 +1,35 @@
/*
* 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 "rf_path.h"
#include <stdint.h>
#include <stdbool.h>
bool set_freq(const uint64_t freq);
bool set_freq_explicit(const uint64_t if_freq_hz, const uint64_t lo_freq_hz,
const rf_path_filter_t path);
#endif/*__TUNING_H__*/

View File

@ -0,0 +1,590 @@
/*
* Copyright 2018 Jared Boone
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_portapack.h"
#include "portapack.h"
/* Pixel data within a font or bitmap byte is "reversed": LSB is left-most pixel. */
static const uint8_t font_fixed_8x16_glyph_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x48, 0x48, 0x48, 0xff, 0x24, 0x24, 0xff, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x78, 0x14, 0x14, 0x14, 0x18, 0x30, 0x50, 0x50, 0x50, 0x3c, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x46, 0x29, 0x29, 0x19, 0x16, 0x68, 0x98, 0x94, 0x94, 0x62, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x14, 0x88, 0x54, 0x72, 0x22, 0x62, 0x9c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x40, 0x00,
0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x02, 0x00,
0x00, 0x00, 0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x5a, 0x5a, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0c, 0x0a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1e, 0x20, 0x20, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1e, 0x20, 0x20, 0x10, 0x0c, 0x10, 0x20, 0x20, 0x10, 0x0e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x30, 0x28, 0x28, 0x24, 0x24, 0x22, 0x7e, 0x20, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7c, 0x04, 0x04, 0x04, 0x3c, 0x40, 0x40, 0x40, 0x40, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x04, 0x02, 0x02, 0x3a, 0x46, 0x42, 0x42, 0x44, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7e, 0x40, 0x20, 0x20, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1c, 0x22, 0x42, 0x42, 0x62, 0x5c, 0x40, 0x40, 0x20, 0x1c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x18, 0x04, 0x18, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x30, 0x40, 0x30, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x30, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1c, 0x22, 0x41, 0x59, 0x55, 0x55, 0x55, 0x39, 0x01, 0x02, 0x3c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x14, 0x14, 0x14, 0x14, 0x22, 0x3e, 0x22, 0x41, 0x41, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x44, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x44, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1e, 0x22, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x22, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x02, 0x7e, 0x02, 0x02, 0x02, 0x02, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x02, 0x7e, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x44, 0x02, 0x02, 0x02, 0x72, 0x42, 0x42, 0x44, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x82, 0x42, 0x22, 0x12, 0x0a, 0x0e, 0x12, 0x22, 0x42, 0x82, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x42, 0x66, 0x66, 0x5a, 0x5a, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x42, 0x46, 0x46, 0x4a, 0x4a, 0x52, 0x52, 0x62, 0x62, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x10, 0x60, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x12, 0x22, 0x22, 0x42, 0x82, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x0c, 0x30, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x22, 0x22, 0x14, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x49, 0x49, 0x55, 0x55, 0x55, 0x22, 0x22, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x22, 0x22, 0x14, 0x08, 0x08, 0x14, 0x22, 0x22, 0x41, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7e, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x02, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00,
0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00,
0x00, 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x7c, 0x42, 0x62, 0x5c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x1a, 0x26, 0x42, 0x42, 0x42, 0x26, 0x1a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x02, 0x02, 0x02, 0x04, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x58, 0x64, 0x42, 0x42, 0x42, 0x64, 0x58, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x7e, 0x02, 0x04, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x70, 0x08, 0x08, 0x7e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x22, 0x22, 0x22, 0x1c, 0x02, 0x3e, 0x42, 0x42, 0x3c,
0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e,
0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x22, 0x12, 0x0a, 0x0e, 0x12, 0x22, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x26, 0x42, 0x42, 0x42, 0x26, 0x1a, 0x02, 0x02, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x42, 0x42, 0x42, 0x64, 0x58, 0x40, 0x40, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x02, 0x02, 0x3c, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x70, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x22, 0x22, 0x36, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x49, 0x55, 0x55, 0x22, 0x22, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x22, 0x22, 0x14, 0x14, 0x14, 0x08, 0x08, 0x04, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x20, 0x10, 0x08, 0x08, 0x04, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x00,
0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const ui_font_t font_fixed_8x16 = {
{ 8, 16 },
font_fixed_8x16_glyph_data,
0x20, 95,
(8 * 16 + 7U) >> 3
};
static const uint8_t font_fixed_24x19_glyph_data[] = {
0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07,
0x00, 0x78, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7f, 0x00, 0x80, 0x77, 0x00, 0xc0, 0x73, 0x00, 0xc0, 0x71, 0x00, 0xc0, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00, 0x00, 0x70, 0x00,
0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3c, 0x00, 0xfc, 0x1f, 0xe0, 0xff, 0x1f, 0xf8, 0xff, 0x07, 0xfc, 0x07, 0x00, 0x3c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f,
0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x3f, 0x3c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0xfe, 0x3f, 0x00, 0xfe, 0x1f, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x38, 0xf8, 0xff, 0x3f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07,
0x00, 0x80, 0x0f, 0x00, 0xc0, 0x0f, 0x00, 0xe0, 0x0f, 0x00, 0xf8, 0x0f, 0x00, 0x7c, 0x0f, 0x00, 0x1e, 0x0f, 0x00, 0x0f, 0x0f, 0xc0, 0x07, 0x0f, 0xe0, 0x01, 0x0f, 0xf0, 0x00, 0x0f, 0x7c, 0x00, 0x0f, 0x1e, 0x00, 0x0f, 0xfe, 0xff, 0x7f, 0xfe, 0xff, 0x7f, 0xfe, 0xff, 0x7f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f,
0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f, 0x1c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0xdc, 0xff, 0x07, 0xfc, 0xff, 0x1f, 0xfc, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07,
0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x00, 0xdc, 0xff, 0x07, 0xfc, 0xff, 0x1f, 0xfc, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07,
0xfc, 0xff, 0x7f, 0xfc, 0xff, 0x7f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x03, 0x00, 0xe0, 0x01, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x0f, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x03, 0x00,
0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf0, 0xff, 0x0f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07,
0xe0, 0xff, 0x07, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0x3c, 0x00, 0x3c, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x3f, 0xf8, 0xff, 0x3f, 0xe0, 0xff, 0x3b, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x1c, 0x00, 0x38, 0x3c, 0x00, 0x3c, 0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xe0, 0xff, 0x07,
};
static const ui_font_t font_fixed_24x19 = {
{ 24, 19 },
font_fixed_24x19_glyph_data,
0x30, 10,
(24 * 19 + 7U) >> 3
};
static const uint8_t font_fixed_16x14_glyph_data[] = {
0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f,
0x00, 0x03, 0x80, 0x03, 0xc0, 0x03, 0xe0, 0x03, 0x70, 0x03, 0x20, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x00, 0x60, 0x00, 0x70, 0x80, 0x3f, 0xf8, 0x1f, 0xfc, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x06, 0x00, 0xfe, 0x7f, 0xfe, 0x7f,
0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x00, 0x60, 0x00, 0x60, 0xc0, 0x3f, 0xc0, 0x7f, 0x00, 0x60, 0x00, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f,
0x00, 0x1c, 0x00, 0x1e, 0x00, 0x1f, 0x80, 0x1b, 0xc0, 0x19, 0xe0, 0x18, 0x70, 0x18, 0x38, 0x18, 0x1c, 0x18, 0xfe, 0x7f, 0xfe, 0x7f, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18,
0xfe, 0x7f, 0xfe, 0x7f, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xf6, 0x1f, 0xfe, 0x3f, 0x0e, 0x70, 0x00, 0x60, 0x00, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f,
0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x00, 0xf6, 0x1f, 0xfe, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f,
0xfe, 0x7f, 0xfe, 0x7f, 0x00, 0x70, 0x00, 0x30, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x07, 0x80, 0x03, 0x80, 0x01, 0xc0, 0x00, 0xe0, 0x00, 0x60, 0x00,
0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f,
0xf8, 0x1f, 0xfc, 0x3f, 0x0e, 0x70, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x7f, 0xf8, 0x6f, 0x00, 0x60, 0x06, 0x60, 0x0e, 0x70, 0xfc, 0x3f, 0xf8, 0x1f,
};
static const ui_font_t font_fixed_16x14 = {
{ 16, 14 },
font_fixed_16x14_glyph_data,
0x30, 10,
(16 * 14 + 7U) >> 3
};
static const uint8_t bitmap_amp_rx_data[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x0c, 0x00, 0x30, 0x0c, 0x00, 0x30, 0x18, 0x00, 0x18, 0x18, 0x00, 0x18, 0x30, 0x00, 0x0c, 0x30, 0x00, 0x0c, 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, 0x80, 0x81, 0x01, 0x80, 0x81, 0x01, 0x00, 0xc3, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x66, 0x00, 0x00, 0x66, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00
};
static const ui_bitmap_t bitmap_amp_rx = {
{ 24, 24 }, bitmap_amp_rx_data
};
static const uint8_t bitmap_amp_tx_data[] = {
0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x66, 0x00, 0x00, 0x66, 0x00, 0x00, 0xc3, 0x00, 0x00, 0xc3, 0x00, 0x80, 0x81, 0x01, 0x80, 0x81, 0x01, 0xc0, 0x00, 0x03, 0xc0, 0x00, 0x03, 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0x30, 0x00, 0x0c, 0x30, 0x00, 0x0c, 0x18, 0x00, 0x18, 0x18, 0x00, 0x18, 0x0c, 0x00, 0x30, 0x0c, 0x00, 0x30, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static const ui_bitmap_t bitmap_amp_tx = {
{ 24, 24 }, bitmap_amp_tx_data
};
static const uint8_t bitmap_antenna_data[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x06, 0x18, 0x60, 0x06, 0x18, 0x60, 0x0c, 0x18, 0x30, 0x0c, 0x18, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x18, 0x0c, 0x30, 0x18, 0x0c, 0x60, 0x18, 0x06, 0x60, 0x18, 0x06, 0xc0, 0x18, 0x03, 0xc0, 0x18, 0x03, 0x80, 0x99, 0x01, 0x80, 0x99, 0x01, 0x00, 0xdb, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00
};
static const ui_bitmap_t bitmap_antenna = {
{ 24, 24 }, bitmap_antenna_data
};
static const uint8_t bitmap_filter_hp_data[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0xf8, 0xc7, 0x03, 0xfc, 0xc7, 0x03, 0x0e, 0xc0, 0x03, 0x06, 0xc0, 0x03, 0x03, 0xc0, 0x03, 0x03, 0xc0, 0x83, 0x01, 0xc0, 0x83, 0x01, 0xc0, 0xc3, 0x00, 0xc0, 0xc3, 0x00, 0xc0, 0x63, 0x00, 0xc0, 0x63, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static const ui_bitmap_t bitmap_filter_hp = {
{ 24, 24 }, bitmap_filter_hp_data
};
static const uint8_t bitmap_filter_lp_data[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0xe3, 0x1f, 0xc0, 0xe3, 0x3f, 0xc0, 0x03, 0x70, 0xc0, 0x03, 0x60, 0xc0, 0x03, 0xc0, 0xc0, 0x03, 0xc0, 0xc0, 0x03, 0x80, 0xc1, 0x03, 0x80, 0xc1, 0x03, 0x00, 0xc3, 0x03, 0x00, 0xc3, 0x03, 0x00, 0xc6, 0x03, 0x00, 0xc6, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static const ui_bitmap_t bitmap_filter_lp = {
{ 24, 24 }, bitmap_filter_lp_data
};
static const uint8_t bitmap_mixer_data[] = {
0x00, 0x7e, 0x00, 0xc0, 0xff, 0x03, 0xe0, 0x81, 0x07, 0x70, 0x00, 0x0e, 0x38, 0x00, 0x1c, 0x7c, 0x00, 0x3e, 0xee, 0x00, 0x77, 0xc6, 0x81, 0x63, 0x86, 0xc3, 0x61, 0x03, 0xe7, 0xc0, 0x03, 0x7e, 0xc0, 0x03, 0x3c, 0xc0, 0x03, 0x3c, 0xc0, 0x03, 0x7e, 0xc0, 0x03, 0xe7, 0xc0, 0x86, 0xc3, 0x61, 0xc6, 0x81, 0x63, 0xee, 0x00, 0x77, 0x7c, 0x00, 0x3e, 0x38, 0x00, 0x1c, 0x70, 0x00, 0x0e, 0xe0, 0x81, 0x07, 0xc0, 0xff, 0x03, 0x00, 0x7e, 0x00
};
static const ui_bitmap_t bitmap_mixer = {
{ 24, 24 }, bitmap_mixer_data
};
static const uint8_t bitmap_oscillator_data[] = {
0x00, 0x7e, 0x00, 0xc0, 0xff, 0x03, 0xe0, 0x81, 0x07, 0x70, 0x00, 0x0e, 0x38, 0x00, 0x1c, 0x1c, 0x00, 0x38, 0x0e, 0x03, 0x70, 0x86, 0x07, 0x60, 0xc6, 0x0f, 0x60, 0xc3, 0x0c, 0xc0, 0xe3, 0x1c, 0xc0, 0x63, 0x18, 0xc6, 0x63, 0x18, 0xc6, 0x03, 0x38, 0xc7, 0x03, 0x30, 0xc3, 0x06, 0xf0, 0x63, 0x06, 0xe0, 0x61, 0x0e, 0xc0, 0x70, 0x1c, 0x00, 0x38, 0x38, 0x00, 0x1c, 0x70, 0x00, 0x0e, 0xe0, 0x81, 0x07, 0xc0, 0xff, 0x03, 0x00, 0x7e, 0x00
};
static const ui_bitmap_t bitmap_oscillator = {
{ 24, 24 }, bitmap_oscillator_data
};
static const uint8_t bitmap_wire_8_data[] = {
0xff, 0xff
};
static const ui_bitmap_t bitmap_wire_8 = {
{ 2, 8 }, bitmap_wire_8_data
};
static const uint8_t bitmap_wire_24_data[] = {
0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00
};
static const ui_bitmap_t bitmap_wire_24 = {
{ 24, 24 }, bitmap_wire_24_data
};
static const uint8_t bitmap_blank_24_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const ui_bitmap_t bitmap_blank_24 = {
{ 24, 24 }, bitmap_blank_24_data
};
static const uint8_t bitmap_waves_rx_data[] = {
0xc0, 0x00, 0x60, 0x00, 0x70, 0x06, 0x30, 0x07, 0x38, 0x03, 0x98, 0x33, 0x98, 0x39, 0x98, 0x19, 0xcc, 0x18, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x18, 0x98, 0x19, 0x98, 0x39, 0x98, 0x33, 0x38, 0x03, 0x30, 0x07, 0x70, 0x06, 0x60, 0x00, 0xc0, 0x00
};
static const ui_bitmap_t bitmap_waves_rx = {
{ 16, 24 }, bitmap_waves_rx_data
};
static const uint8_t bitmap_waves_tx_data[] = {
0x00, 0x03, 0x00, 0x06, 0x60, 0x0e, 0xe0, 0x0c, 0xc0, 0x1c, 0xcc, 0x19, 0x9c, 0x19, 0x98, 0x19, 0x18, 0x33, 0x30, 0x33, 0x30, 0x33, 0x30, 0x33, 0x30, 0x33, 0x30, 0x33, 0x30, 0x33, 0x18, 0x33, 0x98, 0x19, 0x9c, 0x19, 0xcc, 0x19, 0xc0, 0x1c, 0xe0, 0x0c, 0x60, 0x0e, 0x00, 0x06, 0x00, 0x03
};
static const ui_bitmap_t bitmap_waves_tx = {
{ 16, 24 }, bitmap_waves_tx_data
};
__attribute__((unused)) static ui_color_t portapack_color_rgb(
const uint_fast8_t r,
const uint_fast8_t g,
const uint_fast8_t b
) {
const ui_color_t result = {
.v = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3)
};
return result;
}
static const ui_color_t color_background = { 0x001f };
static const ui_color_t color_foreground = { 0xffff };
static ui_point_t portapack_lcd_draw_int(const ui_point_t point, uint64_t value, size_t field_width) {
const ui_point_t point_done = {
.x = point.x + font_fixed_8x16.glyph_size.width * field_width,
.y = point.y
};
ui_point_t point_next = point_done;
for(size_t i=0; i<field_width; i++) {
const char c = ((i == 0) || (value != 0)) ? ('0' + value % 10) : ' ';
value /= 10;
const ui_bitmap_t glyph = portapack_font_glyph(&font_fixed_8x16, c);
point_next.x -= glyph.size.width;
portapack_draw_bitmap(point_next, glyph, color_foreground, color_background);
}
return point_done;
}
static ui_point_t portapack_lcd_draw_string(ui_point_t point, const char* s) {
while(*s) {
const char c = *(s++);
const ui_bitmap_t glyph = portapack_font_glyph(&font_fixed_8x16, c);
portapack_draw_bitmap(point, glyph, color_foreground, color_background);
point.x += glyph.size.width;
}
return point;
}
typedef struct draw_list_t {
const ui_bitmap_t* bitmap;
const ui_point_t point;
} draw_list_t;
static draw_list_t radio_draw_list[] = {
{ &bitmap_antenna, { 32, 64 } },
{ &bitmap_wire_8, { 43, 88 } },
{ &bitmap_wire_24, { 32, 96 } },
{ &bitmap_wire_8, { 43, 120 } },
{ &bitmap_filter_hp, { 32, 128 } },
{ &bitmap_wire_8, { 43, 152 } },
{ &bitmap_mixer, { 32, 160 } },
{ &bitmap_wire_8, { 43, 184 } },
{ &bitmap_amp_rx, { 32, 192 } },
{ &bitmap_wire_8, { 43, 216 } },
{ &bitmap_mixer, { 32, 224 } },
{ &bitmap_wire_8, { 43, 248 } },
{ &bitmap_filter_lp, { 32, 256 } },
{ &bitmap_wire_8, { 43, 280 } },
{ &bitmap_amp_rx, { 32, 288 } },
{ &bitmap_wire_8, { 43, 312 } },
{ &bitmap_oscillator, { 208, 288 } },
{ &bitmap_blank_24, { 60, 60 } },
};
typedef enum {
RADIO_DRAW_LIST_ITEM_ANTENNA = 0,
RADIO_DRAW_LIST_ITEM_RF_AMP = 2,
RADIO_DRAW_LIST_ITEM_IMAGE_FILTER = 4,
RADIO_DRAW_LIST_ITEM_RF_MIXER = 6,
RADIO_DRAW_LIST_ITEM_BB_LNA_AMP = 8,
RADIO_DRAW_LIST_ITEM_BB_MIXER = 10,
RADIO_DRAW_LIST_ITEM_BB_FILTER = 12,
RADIO_DRAW_LIST_ITEM_BB_VGA_AMP = 14,
RADIO_DRAW_LIST_ITEM_CLOCK = 16,
RADIO_DRAW_LIST_ITEM_WAVES = 17,
} radio_draw_list_item_t;
static ui_point_t portapack_ui_label_point(const radio_draw_list_item_t item) {
const uint8_t VALUES_X = 72;
ui_point_t point = { VALUES_X, radio_draw_list[item].point.y + 4 };
return point;
}
static ui_point_t portapack_ui_draw_string(const radio_draw_list_item_t item, const char* s) {
return portapack_lcd_draw_string(portapack_ui_label_point(item), s);
}
static ui_point_t portapack_ui_draw_db(const radio_draw_list_item_t item, const uint32_t db) {
ui_point_t point = portapack_ui_label_point(item);
point = portapack_lcd_draw_int(point, db, 2);
return portapack_lcd_draw_string(point, " dB");
}
static ui_point_t portapack_ui_draw_bw_mhz(const radio_draw_list_item_t item, const uint64_t hz) {
const uint32_t lsd = 1000000 / 100;
const uint32_t round_offset = lsd / 2;
const uint64_t hz_offset = hz + round_offset;
const uint32_t mhz = hz_offset / 1000000;
const uint32_t frac = hz_offset / lsd;
ui_point_t point = portapack_ui_label_point(item);
point = portapack_lcd_draw_int(point, mhz, 2);
point = portapack_lcd_draw_string(point, ".");
point = portapack_lcd_draw_int(point, frac, 2);
return portapack_lcd_draw_string(point, " MHz");
}
static void portapack_draw_radio_path_item(const radio_draw_list_item_t item) {
portapack_draw_bitmap(radio_draw_list[item].point, *radio_draw_list[item].bitmap, color_foreground, color_background);
}
static void portapack_radio_path_item_update(const radio_draw_list_item_t item, const ui_bitmap_t* const bitmap) {
if( bitmap != radio_draw_list[item].bitmap ) {
radio_draw_list[item].bitmap = bitmap;
portapack_draw_radio_path_item(item);
}
}
static rf_path_direction_t portapack_direction = RF_PATH_DIRECTION_OFF;
static bool portapack_lna_on = false;
static void portapack_radio_path_redraw() {
for( size_t i=0; i<ARRAY_SIZEOF(radio_draw_list); i++ ) {
portapack_draw_radio_path_item(i);
}
}
static void portapack_ui_init(void) {
portapack_clear_display(color_background);
portapack_backlight(true);
portapack_radio_path_redraw();
}
static void portapack_ui_deinit(void) {
portapack_clear_display(color_background);
portapack_backlight(false);
}
static void portapack_ui_set_frequency(uint64_t frequency) {
static char last[10] = " ";
ui_point_t point = { 240 - 20, 16 };
uint64_t value = frequency;
char s[10];
for(int i=0; i<10; i++) {
const char c = '0' + value % 10;
s[i] = ((i>=6) && (value == 0)) ? ' ' : c;
value /= 10;
}
for(int i=0; i<10; i++) {
const char c = s[i];
const ui_font_t* const font = (i > 5) ? &font_fixed_24x19 : &font_fixed_16x14;
point.x -= font->glyph_size.width;
if( (i==3) || (i==6) || (i==9) ) {
point.x -= 4;
}
if( c != last[i] ) {
const ui_bitmap_t glyph = portapack_font_glyph(font, c);
if( c == ' ' ) {
/* Blank out leading zeros. */
const ui_rect_t rect = { point, glyph.size };
portapack_fill_rectangle(rect, color_background);
} else {
portapack_draw_bitmap(point, glyph, color_foreground, color_background);
}
last[i] = c;
}
}
}
static void portapack_ui_set_sample_rate(uint32_t sample_rate) {
#if 0
ui_point_t point = { VALUES_X, 320 - 1 * 16 };
portapack_lcd_draw_int(point, sample_rate, 8);
#else
(void)sample_rate;
#endif
}
static void portapack_ui_set_direction(const rf_path_direction_t direction) {
switch(direction) {
case RF_PATH_DIRECTION_TX:
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_WAVES, &bitmap_waves_tx);
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_RF_AMP, portapack_lna_on ? &bitmap_amp_tx : &bitmap_wire_24);
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, &bitmap_amp_tx);
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, &bitmap_wire_24);
portapack_ui_draw_string(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, " ");
break;
case RF_PATH_DIRECTION_RX:
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_WAVES, &bitmap_waves_rx);
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_RF_AMP, portapack_lna_on ? &bitmap_amp_rx : &bitmap_wire_24);
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, &bitmap_amp_rx);
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, &bitmap_amp_rx);
break;
case RF_PATH_DIRECTION_OFF:
default:
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_WAVES, &bitmap_blank_24);
break;
}
portapack_direction = direction;
}
static void portapack_ui_set_filter_bw(uint32_t bandwidth) {
portapack_ui_draw_bw_mhz(RADIO_DRAW_LIST_ITEM_BB_FILTER, bandwidth);
}
static void portapack_ui_set_lna_power(bool lna_on) {
portapack_lna_on = lna_on;
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_RF_AMP, lna_on
? ((portapack_direction == RF_PATH_DIRECTION_TX) ? &bitmap_amp_tx : &bitmap_amp_rx)
: &bitmap_wire_24);
const char* const label = lna_on ? "14 dB" : " ";
portapack_ui_draw_string(RADIO_DRAW_LIST_ITEM_RF_AMP, label);
}
static void portapack_ui_set_bb_lna_gain(const uint32_t gain_db) {
portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, gain_db);
}
static void portapack_ui_set_bb_vga_gain(const uint32_t gain_db) {
portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, gain_db);
}
static void portapack_ui_set_bb_tx_vga_gain(const uint32_t gain_db) {
/* TODO: This function (and code throughout the HackRF project) is mis-labeled?
* According to the MAX2837 datasheet diagram, there is no baseband gain in the TX path.
* This gets called when the TX IF gain is changed.
*/
portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, gain_db);
}
static void portapack_ui_set_first_if_frequency(const uint64_t frequency) {
(void)frequency;
}
static void portapack_ui_set_filter(const rf_path_filter_t filter) {
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_RF_MIXER, (filter == RF_PATH_FILTER_BYPASS) ? &bitmap_wire_24 : &bitmap_mixer);
switch(filter) {
default:
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_IMAGE_FILTER, &bitmap_wire_24);
break;
case RF_PATH_FILTER_LOW_PASS:
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_IMAGE_FILTER, &bitmap_filter_lp);
break;
case RF_PATH_FILTER_HIGH_PASS:
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_IMAGE_FILTER, &bitmap_filter_hp);
break;
}
}
static void portapack_ui_set_antenna_bias(bool antenna_bias) {
(void)antenna_bias;
}
static void portapack_ui_set_clock_source(clock_source_t source) {
ui_point_t label_point = radio_draw_list[RADIO_DRAW_LIST_ITEM_CLOCK].point;
label_point.x -= 0;
label_point.y -= 16;
const char* s = "HRF";
switch(source) {
case CLOCK_SOURCE_EXTERNAL: { s = "EXT"; break; }
case CLOCK_SOURCE_PORTAPACK: { s = "PPK"; break; }
default:
case CLOCK_SOURCE_HACKRF: { s = "HRF"; break; }
}
portapack_lcd_draw_string(label_point, s);
}
static void portapack_ui_set_transceiver_mode(transceiver_mode_t mode) {
(void)mode;
}
static bool portapack_ui_operacake_gpio_compatible(void) {
return false;
}
const hackrf_ui_t portapack_hackrf_ui = {
&portapack_ui_init,
&portapack_ui_deinit,
&portapack_ui_set_frequency,
&portapack_ui_set_sample_rate,
&portapack_ui_set_direction,
&portapack_ui_set_filter_bw,
&portapack_ui_set_lna_power,
&portapack_ui_set_bb_lna_gain,
&portapack_ui_set_bb_vga_gain,
&portapack_ui_set_bb_tx_vga_gain,
&portapack_ui_set_first_if_frequency,
&portapack_ui_set_filter,
&portapack_ui_set_antenna_bias,
&portapack_ui_set_clock_source,
&portapack_ui_set_transceiver_mode,
&portapack_ui_operacake_gpio_compatible,
};
const hackrf_ui_t* portapack_hackrf_ui_init() {
if( portapack() ) {
return &portapack_hackrf_ui;
} else {
return NULL;
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2018 Jared Boone
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __UI_PORTAPACK_H__
#define __UI_PORTAPACK_H__
#include "hackrf_ui.h"
const hackrf_ui_t* portapack_hackrf_ui_init() __attribute__((weak));
#endif/*__UI_PORTAPACK_H__*/

View File

@ -0,0 +1,330 @@
/*
* Copyright 2019 Dominic Spill
*
* 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 "ui_rad1o.h"
#include "rad1o/display.h"
#include "rad1o/draw.h"
#include "rad1o/print.h"
#include "rad1o/render.h"
#include "rad1o/smallfonts.h"
#include "rad1o/ubuntu18.h"
#include <stdio.h>
static uint64_t freq = 0;
static uint32_t sample_rate = 0;
static uint32_t filter_bw = 0;
static rf_path_direction_t direction;
static uint32_t bblna_gain = 0;
static uint32_t bbvga_gain = 0;
static uint32_t bbtxvga_gain = 0;
static bool lna_on = false;
static transceiver_mode_t trx_mode;
static bool enabled = false;
#define BLACK 0b00000000
#define RED 0b11100000
#define RED_DARK 0b01100000
#define GREEN 0b00011100
#define GREEN_DARK 0b00001100
#define BLUE 0b00000011
#define WHITE 0b11111111
#define GREY 0b01001101
static void draw_frequency(void)
{
char tmp[100];
uint32_t mhz;
uint32_t khz;
mhz = freq / 1000000;
khz = (freq - mhz * 1000000) / 1000;
rad1o_setTextColor(BLACK, GREEN);
rad1o_setIntFont(&Font_Ubuntu18pt);
sprintf(tmp, "%4u.%03u", (unsigned int)mhz, (unsigned int)khz);
rad1o_lcdPrint(tmp);
rad1o_setIntFont(&Font_7x8);
rad1o_lcdMoveCrsr(1, 18 - 7);
rad1o_lcdPrint("MHz");
}
static void draw_tx_rx(void)
{
uint8_t bg, fg;
rad1o_setIntFont(&Font_Ubuntu18pt);
bg = BLACK;
fg = GREY;
if (direction == RF_PATH_DIRECTION_OFF) {
fg = WHITE;
}
rad1o_setTextColor(bg, fg);
rad1o_lcdPrint("OFF ");
fg = GREY;
if (direction == RF_PATH_DIRECTION_RX) {
fg = GREEN;
}
rad1o_setTextColor(bg, fg);
rad1o_lcdPrint("RX ");
fg = GREY;
if (direction == RF_PATH_DIRECTION_TX) {
fg = RED;
}
rad1o_setTextColor(bg, fg);
rad1o_lcdPrint("TX");
rad1o_setIntFont(&Font_7x8);
}
static void ui_update(void)
{
char tmp[100];
uint32_t mhz;
uint32_t khz;
if (!enabled) {
return;
}
rad1o_lcdClear();
rad1o_lcdFill(0x00);
rad1o_drawHLine(0, 0, RESX - 1, WHITE);
rad1o_drawVLine(0, 0, RESY - 1, WHITE);
rad1o_drawHLine(RESY - 1, 0, RESX - 1, WHITE);
rad1o_drawVLine(RESX - 1, 0, RESY - 1, WHITE);
rad1o_lcdSetCrsr(25, 2);
rad1o_setTextColor(BLACK, GREEN);
rad1o_lcdPrint("HackRF Mode");
rad1o_lcdNl();
rad1o_drawHLine(11, 0, RESX - 1, WHITE);
rad1o_lcdSetCrsr(2, 12);
if (trx_mode == TRANSCEIVER_MODE_RX_SWEEP) {
rad1o_setIntFont(&Font_Ubuntu18pt);
rad1o_lcdPrint("SWEEP");
} else {
draw_frequency();
}
rad1o_drawHLine(40, 0, RESX - 1, WHITE);
rad1o_lcdSetCrsr(6, 41);
draw_tx_rx();
rad1o_drawHLine(69, 0, RESX - 1, WHITE);
rad1o_setTextColor(BLACK, WHITE);
rad1o_lcdSetCrsr(2, 71);
rad1o_lcdPrint("Rate: ");
mhz = sample_rate / 1000000;
khz = (sample_rate - mhz * 1000000) / 1000;
sprintf(tmp, "%2u.%03u MHz", (unsigned int)mhz, (unsigned int)khz);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_lcdMoveCrsr(2, 0);
rad1o_lcdPrint("Filter: ");
mhz = filter_bw / 1000000;
khz = (filter_bw - mhz * 1000000) / 1000;
sprintf(tmp, "%2u.%03u MHz", (unsigned int)mhz, (unsigned int)khz);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_drawHLine(88, 0, RESX - 1, WHITE);
rad1o_setTextColor(BLACK, WHITE);
rad1o_lcdSetCrsr(2, 90);
rad1o_lcdPrint(" Gains");
rad1o_lcdNl();
rad1o_setTextColor(BLACK, GREEN);
rad1o_lcdMoveCrsr(2, 2);
rad1o_lcdPrint("AMP: ");
if (lna_on) {
rad1o_setTextColor(BLACK, RED);
rad1o_lcdPrint("ON ");
} else {
rad1o_lcdPrint("OFF");
}
rad1o_setTextColor(BLACK, RED_DARK);
if (direction == RF_PATH_DIRECTION_TX) {
rad1o_setTextColor(BLACK, RED);
}
sprintf(tmp, " TX: %u dB", (unsigned int)bbtxvga_gain);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_lcdMoveCrsr(2, 0);
rad1o_setTextColor(BLACK, GREEN_DARK);
if (direction == RF_PATH_DIRECTION_RX) {
rad1o_setTextColor(BLACK, GREEN);
}
sprintf(tmp, "LNA: %2u dB", (unsigned int)bblna_gain);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_lcdMoveCrsr(2, 0);
sprintf(tmp, "VGA: %2u dB", (unsigned int)bbvga_gain);
rad1o_lcdPrint(tmp);
rad1o_lcdNl();
rad1o_lcdDisplay();
// Don't ask...
ssp1_set_mode_max2837();
}
static void rad1o_ui_init(void)
{
rad1o_lcdInit();
enabled = true;
ui_update();
}
static void rad1o_ui_deinit(void)
{
rad1o_lcdDeInit();
enabled = false;
// Don't ask...
ssp1_set_mode_max2837();
}
static void rad1o_ui_set_frequency(uint64_t frequency)
{
freq = frequency;
if (TRANSCEIVER_MODE_RX_SWEEP == trx_mode) {
} else {
ui_update();
}
}
static void rad1o_ui_set_sample_rate(uint32_t _sample_rate)
{
sample_rate = _sample_rate;
ui_update();
}
static void rad1o_ui_set_direction(const rf_path_direction_t _direction)
{
direction = _direction;
ui_update();
}
static void rad1o_ui_set_filter_bw(uint32_t bandwidth)
{
filter_bw = bandwidth;
ui_update();
}
static void rad1o_ui_set_lna_power(bool _lna_on)
{
lna_on = _lna_on;
ui_update();
}
static void rad1o_ui_set_bb_lna_gain(const uint32_t gain_db)
{
bblna_gain = gain_db;
ui_update();
}
static void rad1o_ui_set_bb_vga_gain(const uint32_t gain_db)
{
bbvga_gain = gain_db;
ui_update();
}
static void rad1o_ui_set_bb_tx_vga_gain(const uint32_t gain_db)
{
bbtxvga_gain = gain_db;
ui_update();
}
static void rad1o_ui_set_first_if_frequency(const uint64_t frequency
__attribute__((unused)))
{
// Not implemented
}
static void rad1o_ui_set_filter(const rf_path_filter_t filter
__attribute__((unused)))
{
// Not implemented
}
static void rad1o_ui_set_antenna_bias(bool antenna_bias __attribute__((unused)))
{
// Not implemented
}
static void rad1o_ui_set_clock_source(clock_source_t source
__attribute__((unused)))
{
// Not implemented
}
static void rad1o_ui_set_transceiver_mode(transceiver_mode_t mode)
{
trx_mode = mode;
ui_update();
}
static bool rad1o_ui_operacake_gpio_compatible(void)
{
return true;
}
static const hackrf_ui_t rad1o_ui = {
&rad1o_ui_init,
&rad1o_ui_deinit,
&rad1o_ui_set_frequency,
&rad1o_ui_set_sample_rate,
&rad1o_ui_set_direction,
&rad1o_ui_set_filter_bw,
&rad1o_ui_set_lna_power,
&rad1o_ui_set_bb_lna_gain,
&rad1o_ui_set_bb_vga_gain,
&rad1o_ui_set_bb_tx_vga_gain,
&rad1o_ui_set_first_if_frequency,
&rad1o_ui_set_filter,
&rad1o_ui_set_antenna_bias,
&rad1o_ui_set_clock_source,
&rad1o_ui_set_transceiver_mode,
&rad1o_ui_operacake_gpio_compatible,
};
const hackrf_ui_t *rad1o_ui_setup(void)
{
return &rad1o_ui;
}

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