Add software
This commit is contained in:
@ -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
|
@ -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
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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));
|
2
Software/portapack-mayhem/hackrf/firmware/common/README
Normal file
2
Software/portapack-mayhem/hackrf/firmware/common/README
Normal file
@ -0,0 +1,2 @@
|
||||
This directory contains things shared by multiple HackRF firmware
|
||||
implementations.
|
45
Software/portapack-mayhem/hackrf/firmware/common/bitband.c
Normal file
45
Software/portapack-mayhem/hackrf/firmware/common/bitband.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "bitband.h"
|
||||
|
||||
volatile uint32_t* peripheral_bitband_address(volatile void* const address, const uint_fast8_t bit_number) {
|
||||
const uint32_t bit_band_base = 0x42000000;
|
||||
const uint32_t byte_offset = (uint32_t)address - 0x40000000;
|
||||
const uint32_t bit_word_offset = (byte_offset * 32) + (bit_number * 4);
|
||||
const uint32_t bit_word_address = bit_band_base + bit_word_offset;
|
||||
return (volatile uint32_t*)bit_word_address;
|
||||
}
|
||||
|
||||
void peripheral_bitband_set(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
|
||||
volatile uint32_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
|
||||
*bitband_address = 1;
|
||||
}
|
||||
|
||||
void peripheral_bitband_clear(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
|
||||
volatile uint32_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
|
||||
*bitband_address = 0;
|
||||
}
|
||||
|
||||
uint32_t peripheral_bitband_get(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
|
||||
volatile uint32_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
|
||||
return *bitband_address;
|
||||
}
|
32
Software/portapack-mayhem/hackrf/firmware/common/bitband.h
Normal file
32
Software/portapack-mayhem/hackrf/firmware/common/bitband.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __BITBAND_H__
|
||||
#define __BITBAND_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
volatile uint32_t* peripheral_bitband_address(volatile void* const address, const uint_fast8_t bit_number);
|
||||
void peripheral_bitband_set(volatile void* const peripheral_address, const uint_fast8_t bit_number);
|
||||
void peripheral_bitband_clear(volatile void* const peripheral_address, const uint_fast8_t bit_number);
|
||||
uint32_t peripheral_bitband_get(volatile void* const peripheral_address, const uint_fast8_t bit_number);
|
||||
|
||||
#endif//__BITBAND_H__
|
@ -0,0 +1,4 @@
|
||||
configure_file(
|
||||
${SRC}
|
||||
${DEST}
|
||||
)
|
101
Software/portapack-mayhem/hackrf/firmware/common/cpld_jtag.c
Normal file
101
Software/portapack-mayhem/hackrf/firmware/common/cpld_jtag.c
Normal 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;
|
||||
}
|
62
Software/portapack-mayhem/hackrf/firmware/common/cpld_jtag.h
Normal file
62
Software/portapack-mayhem/hackrf/firmware/common/cpld_jtag.h
Normal 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__
|
418
Software/portapack-mayhem/hackrf/firmware/common/cpld_xc2c.c
Normal file
418
Software/portapack-mayhem/hackrf/firmware/common/cpld_xc2c.c
Normal 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;
|
||||
}
|
75
Software/portapack-mayhem/hackrf/firmware/common/cpld_xc2c.h
Normal file
75
Software/portapack-mayhem/hackrf/firmware/common/cpld_xc2c.h
Normal 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__*/
|
49
Software/portapack-mayhem/hackrf/firmware/common/crc.c
Normal file
49
Software/portapack-mayhem/hackrf/firmware/common/crc.c
Normal 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;
|
||||
}
|
38
Software/portapack-mayhem/hackrf/firmware/common/crc.h
Normal file
38
Software/portapack-mayhem/hackrf/firmware/common/crc.h
Normal 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__
|
@ -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);
|
||||
}
|
@ -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__
|
62
Software/portapack-mayhem/hackrf/firmware/common/gpdma.c
Normal file
62
Software/portapack-mayhem/hackrf/firmware/common/gpdma.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2013 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <gpdma.h>
|
||||
|
||||
#include <libopencm3/lpc43xx/gpdma.h>
|
||||
|
||||
void gpdma_controller_enable() {
|
||||
GPDMA_CONFIG |= GPDMA_CONFIG_E(1);
|
||||
while( (GPDMA_CONFIG & GPDMA_CONFIG_E_MASK) == 0 );
|
||||
}
|
||||
|
||||
void gpdma_channel_enable(const uint_fast8_t channel) {
|
||||
GPDMA_CCONFIG(channel) |= GPDMA_CCONFIG_E(1);
|
||||
}
|
||||
|
||||
void gpdma_channel_disable(const uint_fast8_t channel) {
|
||||
GPDMA_CCONFIG(channel) &= ~GPDMA_CCONFIG_E_MASK;
|
||||
while( (GPDMA_ENBLDCHNS & GPDMA_ENBLDCHNS_ENABLEDCHANNELS(1 << channel)) );
|
||||
}
|
||||
|
||||
void gpdma_channel_interrupt_tc_clear(const uint_fast8_t channel) {
|
||||
GPDMA_INTTCCLEAR = GPDMA_INTTCCLEAR_INTTCCLEAR(1 << channel);
|
||||
}
|
||||
|
||||
void gpdma_channel_interrupt_error_clear(const uint_fast8_t channel) {
|
||||
GPDMA_INTERRCLR = GPDMA_INTERRCLR_INTERRCLR(1 << channel);
|
||||
}
|
||||
|
||||
void gpdma_lli_enable_interrupt(gpdma_lli_t* const lli) {
|
||||
lli->ccontrol |= GPDMA_CCONTROL_I(1);
|
||||
}
|
||||
|
||||
void gpdma_lli_create_loop(gpdma_lli_t* const lli, const size_t lli_count) {
|
||||
for(size_t i=0; i<lli_count; i++) {
|
||||
gpdma_lli_t* const next_lli = &lli[(i + 1) % lli_count];
|
||||
lli[i].clli = (lli[i].clli & ~GPDMA_CLLI_LLI_MASK) | GPDMA_CLLI_LLI((uint32_t)next_lli >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
void gpdma_lli_create_oneshot(gpdma_lli_t* const lli, const size_t lli_count) {
|
||||
gpdma_lli_create_loop(lli, lli_count);
|
||||
lli[lli_count - 1].clli &= ~GPDMA_CLLI_LLI_MASK;
|
||||
}
|
43
Software/portapack-mayhem/hackrf/firmware/common/gpdma.h
Normal file
43
Software/portapack-mayhem/hackrf/firmware/common/gpdma.h
Normal 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__*/
|
38
Software/portapack-mayhem/hackrf/firmware/common/gpio.h
Normal file
38
Software/portapack-mayhem/hackrf/firmware/common/gpio.h
Normal 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__*/
|
58
Software/portapack-mayhem/hackrf/firmware/common/gpio_lpc.c
Normal file
58
Software/portapack-mayhem/hackrf/firmware/common/gpio_lpc.c
Normal 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;
|
||||
}
|
70
Software/portapack-mayhem/hackrf/firmware/common/gpio_lpc.h
Normal file
70
Software/portapack-mayhem/hackrf/firmware/common/gpio_lpc.h
Normal 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__*/
|
930
Software/portapack-mayhem/hackrf/firmware/common/hackrf_core.c
Normal file
930
Software/portapack-mayhem/hackrf/firmware/common/hackrf_core.c
Normal 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);
|
||||
}
|
||||
}
|
330
Software/portapack-mayhem/hackrf/firmware/common/hackrf_core.h
Normal file
330
Software/portapack-mayhem/hackrf/firmware/common/hackrf_core.h
Normal 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 */
|
104
Software/portapack-mayhem/hackrf/firmware/common/hackrf_ui.c
Normal file
104
Software/portapack-mayhem/hackrf/firmware/common/hackrf_ui.c
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
71
Software/portapack-mayhem/hackrf/firmware/common/hackrf_ui.h
Normal file
71
Software/portapack-mayhem/hackrf/firmware/common/hackrf_ui.h
Normal 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
|
39
Software/portapack-mayhem/hackrf/firmware/common/i2c_bus.c
Normal file
39
Software/portapack-mayhem/hackrf/firmware/common/i2c_bus.c
Normal 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);
|
||||
}
|
52
Software/portapack-mayhem/hackrf/firmware/common/i2c_bus.h
Normal file
52
Software/portapack-mayhem/hackrf/firmware/common/i2c_bus.h
Normal 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__*/
|
79
Software/portapack-mayhem/hackrf/firmware/common/i2c_lpc.c
Normal file
79
Software/portapack-mayhem/hackrf/firmware/common/i2c_lpc.c
Normal 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;
|
||||
}
|
44
Software/portapack-mayhem/hackrf/firmware/common/i2c_lpc.h
Normal file
44
Software/portapack-mayhem/hackrf/firmware/common/i2c_lpc.h
Normal 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__*/
|
@ -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}"
|
26
Software/portapack-mayhem/hackrf/firmware/common/m0_sleep.c
Normal file
26
Software/portapack-mayhem/hackrf/firmware/common/m0_sleep.c
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
349
Software/portapack-mayhem/hackrf/firmware/common/max2837.c
Normal file
349
Software/portapack-mayhem/hackrf/firmware/common/max2837.c
Normal 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;
|
||||
}
|
92
Software/portapack-mayhem/hackrf/firmware/common/max2837.h
Normal file
92
Software/portapack-mayhem/hackrf/firmware/common/max2837.h
Normal 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
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
236
Software/portapack-mayhem/hackrf/firmware/common/max2871.c
Normal file
236
Software/portapack-mayhem/hackrf/firmware/common/max2871.c
Normal 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);
|
||||
}
|
||||
|
21
Software/portapack-mayhem/hackrf/firmware/common/max2871.h
Normal file
21
Software/portapack-mayhem/hackrf/firmware/common/max2871.h
Normal 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
|
299
Software/portapack-mayhem/hackrf/firmware/common/max2871_regs.c
Normal file
299
Software/portapack-mayhem/hackrf/firmware/common/max2871_regs.c
Normal 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;
|
||||
}
|
@ -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
|
102
Software/portapack-mayhem/hackrf/firmware/common/max5864.c
Normal file
102
Software/portapack-mayhem/hackrf/firmware/common/max5864.c
Normal 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);
|
||||
}
|
44
Software/portapack-mayhem/hackrf/firmware/common/max5864.h
Normal file
44
Software/portapack-mayhem/hackrf/firmware/common/max5864.h
Normal 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
|
@ -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);
|
||||
}
|
@ -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__*/
|
144
Software/portapack-mayhem/hackrf/firmware/common/mixer.c
Normal file
144
Software/portapack-mayhem/hackrf/firmware/common/mixer.c
Normal 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
|
||||
}
|
52
Software/portapack-mayhem/hackrf/firmware/common/mixer.h
Normal file
52
Software/portapack-mayhem/hackrf/firmware/common/mixer.h
Normal 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
|
414
Software/portapack-mayhem/hackrf/firmware/common/operacake.c
Normal file
414
Software/portapack-mayhem/hackrf/firmware/common/operacake.c
Normal 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;
|
||||
}
|
60
Software/portapack-mayhem/hackrf/firmware/common/operacake.h
Normal file
60
Software/portapack-mayhem/hackrf/firmware/common/operacake.h
Normal 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 */
|
@ -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);
|
||||
}
|
@ -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 */
|
577
Software/portapack-mayhem/hackrf/firmware/common/portapack.c
Normal file
577
Software/portapack-mayhem/hackrf/firmware/common/portapack.c
Normal 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;
|
||||
}
|
||||
}
|
95
Software/portapack-mayhem/hackrf/firmware/common/portapack.h
Normal file
95
Software/portapack-mayhem/hackrf/firmware/common/portapack.h
Normal 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__*/
|
127
Software/portapack-mayhem/hackrf/firmware/common/rad1o/decoder.c
Normal file
127
Software/portapack-mayhem/hackrf/firmware/common/rad1o/decoder.c
Normal 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;
|
||||
}
|
@ -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
|
180
Software/portapack-mayhem/hackrf/firmware/common/rad1o/display.c
Normal file
180
Software/portapack-mayhem/hackrf/firmware/common/rad1o/display.c
Normal 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();
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
162
Software/portapack-mayhem/hackrf/firmware/common/rad1o/render.c
Normal file
162
Software/portapack-mayhem/hackrf/firmware/common/rad1o/render.c
Normal 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;
|
||||
}
|
@ -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
|
@ -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 };
|
@ -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
|
3419
Software/portapack-mayhem/hackrf/firmware/common/rad1o/ubuntu18.c
Normal file
3419
Software/portapack-mayhem/hackrf/firmware/common/rad1o/ubuntu18.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
#ifndef __RAD1O_UBUNTU18_H__
|
||||
#define __RAD1O_UBUNTU18_H__
|
||||
#include "fonts.h"
|
||||
|
||||
extern const struct FONT_DEF Font_Ubuntu18pt;
|
||||
|
||||
#endif
|
454
Software/portapack-mayhem/hackrf/firmware/common/rf_path.c
Normal file
454
Software/portapack-mayhem/hackrf/firmware/common/rf_path.c
Normal 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);
|
||||
}
|
84
Software/portapack-mayhem/hackrf/firmware/common/rf_path.h
Normal file
84
Software/portapack-mayhem/hackrf/firmware/common/rf_path.h
Normal 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__*/
|
287
Software/portapack-mayhem/hackrf/firmware/common/rffc5071.c
Normal file
287
Software/portapack-mayhem/hackrf/firmware/common/rffc5071.c
Normal 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);
|
||||
}
|
71
Software/portapack-mayhem/hackrf/firmware/common/rffc5071.h
Normal file
71
Software/portapack-mayhem/hackrf/firmware/common/rffc5071.h
Normal 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
|
@ -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
|
184
Software/portapack-mayhem/hackrf/firmware/common/rffc5071_spi.c
Normal file
184
Software/portapack-mayhem/hackrf/firmware/common/rffc5071_spi.c
Normal 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);
|
||||
}
|
||||
}
|
@ -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
|
106
Software/portapack-mayhem/hackrf/firmware/common/rom_iap.c
Normal file
106
Software/portapack-mayhem/hackrf/firmware/common/rom_iap.c
Normal 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;
|
||||
}
|
121
Software/portapack-mayhem/hackrf/firmware/common/rom_iap.h
Normal file
121
Software/portapack-mayhem/hackrf/firmware/common/rom_iap.h
Normal 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__
|
1764
Software/portapack-mayhem/hackrf/firmware/common/sct.h
Normal file
1764
Software/portapack-mayhem/hackrf/firmware/common/sct.h
Normal file
File diff suppressed because it is too large
Load Diff
307
Software/portapack-mayhem/hackrf/firmware/common/sgpio.c
Normal file
307
Software/portapack-mayhem/hackrf/firmware/common/sgpio.c
Normal 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
|
59
Software/portapack-mayhem/hackrf/firmware/common/sgpio.h
Normal file
59
Software/portapack-mayhem/hackrf/firmware/common/sgpio.h
Normal 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__
|
291
Software/portapack-mayhem/hackrf/firmware/common/si5351c.c
Normal file
291
Software/portapack-mayhem/hackrf/firmware/common/si5351c.c
Normal 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);
|
||||
}
|
100
Software/portapack-mayhem/hackrf/firmware/common/si5351c.h
Normal file
100
Software/portapack-mayhem/hackrf/firmware/common/si5351c.h
Normal 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 */
|
38
Software/portapack-mayhem/hackrf/firmware/common/spi_bus.c
Normal file
38
Software/portapack-mayhem/hackrf/firmware/common/spi_bus.c
Normal 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);
|
||||
}
|
49
Software/portapack-mayhem/hackrf/firmware/common/spi_bus.h
Normal file
49
Software/portapack-mayhem/hackrf/firmware/common/spi_bus.h
Normal 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__*/
|
109
Software/portapack-mayhem/hackrf/firmware/common/spi_ssp.c
Normal file
109
Software/portapack-mayhem/hackrf/firmware/common/spi_ssp.c
Normal 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);
|
||||
}
|
46
Software/portapack-mayhem/hackrf/firmware/common/spi_ssp.h
Normal file
46
Software/portapack-mayhem/hackrf/firmware/common/spi_ssp.h
Normal 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__*/
|
36
Software/portapack-mayhem/hackrf/firmware/common/streaming.c
Normal file
36
Software/portapack-mayhem/hackrf/firmware/common/streaming.c
Normal 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);
|
||||
}
|
31
Software/portapack-mayhem/hackrf/firmware/common/streaming.h
Normal file
31
Software/portapack-mayhem/hackrf/firmware/common/streaming.h
Normal 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__*/
|
154
Software/portapack-mayhem/hackrf/firmware/common/tuning.c
Normal file
154
Software/portapack-mayhem/hackrf/firmware/common/tuning.c
Normal 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;
|
||||
}
|
35
Software/portapack-mayhem/hackrf/firmware/common/tuning.h
Normal file
35
Software/portapack-mayhem/hackrf/firmware/common/tuning.h
Normal 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__*/
|
590
Software/portapack-mayhem/hackrf/firmware/common/ui_portapack.c
Normal file
590
Software/portapack-mayhem/hackrf/firmware/common/ui_portapack.c
Normal 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;
|
||||
}
|
||||
}
|
@ -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__*/
|
330
Software/portapack-mayhem/hackrf/firmware/common/ui_rad1o.c
Normal file
330
Software/portapack-mayhem/hackrf/firmware/common/ui_rad1o.c
Normal 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;
|
||||
}
|
29
Software/portapack-mayhem/hackrf/firmware/common/ui_rad1o.h
Normal file
29
Software/portapack-mayhem/hackrf/firmware/common/ui_rad1o.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __UI_RAD1O_H__
|
||||
#define __UI_RAD1O_H__
|
||||
|
||||
#include "hackrf_ui.h"
|
||||
|
||||
const hackrf_ui_t *rad1o_ui_setup(void) __attribute__((weak));
|
||||
|
||||
#endif /*__UI_RAD1O_H__*/
|
670
Software/portapack-mayhem/hackrf/firmware/common/usb.c
Normal file
670
Software/portapack-mayhem/hackrf/firmware/common/usb.c
Normal file
@ -0,0 +1,670 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "usb_type.h"
|
||||
#include "usb_queue.h"
|
||||
#include "usb_standard_request.h"
|
||||
|
||||
#include <libopencm3/lpc43xx/creg.h>
|
||||
#include <libopencm3/lpc43xx/m4/nvic.h>
|
||||
#include <libopencm3/lpc43xx/rgu.h>
|
||||
#include <libopencm3/lpc43xx/usb.h>
|
||||
|
||||
usb_device_t* usb_device_usb0 = 0;
|
||||
|
||||
usb_queue_head_t usb_qh[12] ATTR_ALIGNED(2048);
|
||||
|
||||
#define USB_QH_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1))
|
||||
|
||||
usb_queue_head_t* usb_queue_head(
|
||||
const uint_fast8_t endpoint_address
|
||||
) {
|
||||
return &usb_qh[USB_QH_INDEX(endpoint_address)];
|
||||
}
|
||||
|
||||
usb_endpoint_t* usb_endpoint_from_address(
|
||||
const uint_fast8_t endpoint_address
|
||||
) {
|
||||
return (usb_endpoint_t*)usb_queue_head(endpoint_address)->_reserved_0;
|
||||
}
|
||||
|
||||
static uint_fast8_t usb_endpoint_address(
|
||||
const usb_transfer_direction_t direction,
|
||||
const uint_fast8_t number
|
||||
) {
|
||||
return ((direction == USB_TRANSFER_DIRECTION_IN) ? 0x80 : 0x00) + number;
|
||||
}
|
||||
|
||||
static bool usb_endpoint_is_in(const uint_fast8_t endpoint_address) {
|
||||
return (endpoint_address & 0x80) ? true : false;
|
||||
}
|
||||
|
||||
static uint_fast8_t usb_endpoint_number(const uint_fast8_t endpoint_address) {
|
||||
return (endpoint_address & 0xF);
|
||||
}
|
||||
|
||||
void usb_peripheral_reset() {
|
||||
RESET_CTRL0 = RESET_CTRL0_USB0_RST;
|
||||
RESET_CTRL0 = 0;
|
||||
|
||||
while( (RESET_ACTIVE_STATUS0 & RESET_CTRL0_USB0_RST) == 0 );
|
||||
}
|
||||
|
||||
void usb_phy_enable() {
|
||||
CREG_CREG0 &= ~CREG_CREG0_USB0PHY;
|
||||
}
|
||||
|
||||
static void usb_clear_pending_interrupts(const uint32_t mask) {
|
||||
USB0_ENDPTNAK = mask;
|
||||
USB0_ENDPTNAKEN = mask;
|
||||
USB0_USBSTS_D = mask;
|
||||
USB0_ENDPTSETUPSTAT = USB0_ENDPTSETUPSTAT & mask;
|
||||
USB0_ENDPTCOMPLETE = USB0_ENDPTCOMPLETE & mask;
|
||||
}
|
||||
|
||||
static void usb_clear_all_pending_interrupts() {
|
||||
usb_clear_pending_interrupts(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static void usb_wait_for_endpoint_priming_to_finish(const uint32_t mask) {
|
||||
// Wait until controller has parsed new transfer descriptors and prepared
|
||||
// receive buffers.
|
||||
while( USB0_ENDPTPRIME & mask );
|
||||
}
|
||||
|
||||
static void usb_flush_endpoints(const uint32_t mask) {
|
||||
// Clear any primed buffers. If a packet is in progress, that transfer
|
||||
// will continue until completion.
|
||||
USB0_ENDPTFLUSH = mask;
|
||||
}
|
||||
|
||||
static void usb_wait_for_endpoint_flushing_to_finish(const uint32_t mask) {
|
||||
// Wait until controller has flushed all endpoints / cleared any primed
|
||||
// buffers.
|
||||
while( USB0_ENDPTFLUSH & mask );
|
||||
}
|
||||
|
||||
static void usb_flush_primed_endpoints(const uint32_t mask) {
|
||||
usb_wait_for_endpoint_priming_to_finish(mask);
|
||||
usb_flush_endpoints(mask);
|
||||
usb_wait_for_endpoint_flushing_to_finish(mask);
|
||||
}
|
||||
|
||||
static void usb_flush_all_primed_endpoints() {
|
||||
usb_flush_primed_endpoints(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static void usb_endpoint_set_type(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_type_t transfer_type
|
||||
) {
|
||||
// NOTE: UM10503 section 23.6.24 "Endpoint 1 to 5 control registers" says
|
||||
// that the disabled side of an endpoint must be set to a non-control type
|
||||
// (e.g. bulk, interrupt, or iso).
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
USB0_ENDPTCTRL(endpoint_number)
|
||||
= ( USB0_ENDPTCTRL(endpoint_number)
|
||||
& ~(USB0_ENDPTCTRL_TXT1_0_MASK | USB0_ENDPTCTRL_RXT_MASK)
|
||||
)
|
||||
| ( USB0_ENDPTCTRL_TXT1_0(transfer_type)
|
||||
| USB0_ENDPTCTRL_RXT(transfer_type)
|
||||
);
|
||||
}
|
||||
|
||||
static void usb_endpoint_enable(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_TXE | USB0_ENDPTCTRL_TXR);
|
||||
} else {
|
||||
USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_RXE | USB0_ENDPTCTRL_RXR);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_endpoint_clear_pending_interrupts(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
usb_clear_pending_interrupts(USB0_ENDPTCOMPLETE_ETCE(1 << endpoint_number));
|
||||
} else {
|
||||
usb_clear_pending_interrupts(USB0_ENDPTCOMPLETE_ERCE(1 << endpoint_number));
|
||||
}
|
||||
}
|
||||
|
||||
void usb_endpoint_disable(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_TXE);
|
||||
} else {
|
||||
USB0_ENDPTCTRL(endpoint_number) &= ~(USB0_ENDPTCTRL_RXE);
|
||||
}
|
||||
usb_queue_flush_endpoint(endpoint);
|
||||
usb_endpoint_clear_pending_interrupts(endpoint);
|
||||
usb_endpoint_flush(endpoint);
|
||||
}
|
||||
|
||||
void usb_endpoint_prime(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
usb_transfer_descriptor_t* const first_td
|
||||
) {
|
||||
usb_queue_head_t* const qh = usb_queue_head(endpoint->address);
|
||||
|
||||
qh->next_dtd_pointer = first_td;
|
||||
qh->total_bytes
|
||||
&= ~( USB_TD_DTD_TOKEN_STATUS_ACTIVE
|
||||
| USB_TD_DTD_TOKEN_STATUS_HALTED
|
||||
)
|
||||
;
|
||||
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
USB0_ENDPTPRIME = USB0_ENDPTPRIME_PETB(1 << endpoint_number);
|
||||
} else {
|
||||
USB0_ENDPTPRIME = USB0_ENDPTPRIME_PERB(1 << endpoint_number);
|
||||
}
|
||||
}
|
||||
|
||||
static bool usb_endpoint_is_priming(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PETB(1 << endpoint_number);
|
||||
} else {
|
||||
return USB0_ENDPTPRIME & USB0_ENDPTPRIME_PERB(1 << endpoint_number);
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule an already filled-in transfer descriptor for execution on
|
||||
// the given endpoint, waiting until the endpoint has finished.
|
||||
void usb_endpoint_schedule_wait(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
usb_transfer_descriptor_t* const td
|
||||
) {
|
||||
// Ensure that endpoint is ready to be primed.
|
||||
// It may have been flushed due to an aborted transaction.
|
||||
// TODO: This should be preceded by a flush?
|
||||
while( usb_endpoint_is_ready(endpoint) );
|
||||
|
||||
td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
||||
|
||||
usb_endpoint_prime(endpoint, td);
|
||||
}
|
||||
|
||||
// Schedule an already filled-in transfer descriptor for execution on
|
||||
// the given endpoint, appending to the end of the endpoint's queue if
|
||||
// there are pending TDs. Note that this requires that one knows the
|
||||
// tail of the endpoint's TD queue. Moreover, the user is responsible
|
||||
// for setting the TERMINATE bit of next_dtd_pointer if needed.
|
||||
void usb_endpoint_schedule_append(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
usb_transfer_descriptor_t* const tail_td,
|
||||
usb_transfer_descriptor_t* const new_td
|
||||
) {
|
||||
bool done;
|
||||
|
||||
tail_td->next_dtd_pointer = new_td;
|
||||
|
||||
if (usb_endpoint_is_priming(endpoint)) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
USB0_USBCMD_D |= USB0_USBCMD_D_ATDTW;
|
||||
done = usb_endpoint_is_ready(endpoint);
|
||||
} while (!(USB0_USBCMD_D & USB0_USBCMD_D_ATDTW));
|
||||
|
||||
USB0_USBCMD_D &= ~USB0_USBCMD_D_ATDTW;
|
||||
if(!done) {
|
||||
usb_endpoint_prime(endpoint, new_td);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_endpoint_flush(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
usb_queue_flush_endpoint(endpoint);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FETB(1 << endpoint_number));
|
||||
} else {
|
||||
usb_flush_primed_endpoints(USB0_ENDPTFLUSH_FERB(1 << endpoint_number));
|
||||
}
|
||||
}
|
||||
/*
|
||||
static bool usb_endpoint_is_flushing(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
return USB0_ENDPTFLUSH & USB0_ENDPTFLUSH_FETB(1 << endpoint_number);
|
||||
} else {
|
||||
return USB0_ENDPTFLUSH & USB0_ENDPTFLUSH_FERB(1 << endpoint_number);
|
||||
}
|
||||
}
|
||||
*/
|
||||
bool usb_endpoint_is_ready(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
return USB0_ENDPTSTAT & USB0_ENDPTSTAT_ETBR(1 << endpoint_number);
|
||||
} else {
|
||||
return USB0_ENDPTSTAT & USB0_ENDPTSTAT_ERBR(1 << endpoint_number);
|
||||
}
|
||||
}
|
||||
|
||||
bool usb_endpoint_is_complete(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
return USB0_ENDPTCOMPLETE & USB0_ENDPTCOMPLETE_ETCE(1 << endpoint_number);
|
||||
} else {
|
||||
return USB0_ENDPTCOMPLETE & USB0_ENDPTCOMPLETE_ERCE(1 << endpoint_number);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_endpoint_stall(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
// Endpoint is to be stalled as a pair -- both OUT and IN.
|
||||
// See UM10503 section 23.10.5.2 "Stalling"
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
USB0_ENDPTCTRL(endpoint_number) |= (USB0_ENDPTCTRL_RXS | USB0_ENDPTCTRL_TXS);
|
||||
|
||||
// TODO: Also need to reset data toggle in both directions?
|
||||
}
|
||||
|
||||
void usb_endpoint_reset_data_toggle(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const uint_fast8_t endpoint_number = usb_endpoint_number(endpoint->address);
|
||||
if( usb_endpoint_is_in(endpoint->address) ) {
|
||||
USB0_ENDPTCTRL(endpoint_number) |= USB0_ENDPTCTRL_TXR;
|
||||
} else {
|
||||
USB0_ENDPTCTRL(endpoint_number) |= USB0_ENDPTCTRL_RXR;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_controller_run() {
|
||||
USB0_USBCMD_D |= USB0_USBCMD_D_RS;
|
||||
}
|
||||
|
||||
static void usb_controller_stop() {
|
||||
USB0_USBCMD_D &= ~USB0_USBCMD_D_RS;
|
||||
}
|
||||
|
||||
static uint_fast8_t usb_controller_is_resetting() {
|
||||
return (USB0_USBCMD_D & USB0_USBCMD_D_RST) != 0;
|
||||
}
|
||||
|
||||
static void usb_controller_set_device_mode() {
|
||||
// Set USB0 peripheral mode
|
||||
USB0_USBMODE_D = USB0_USBMODE_D_CM1_0(2);
|
||||
|
||||
// Set device-related OTG flags
|
||||
// OTG termination: controls pull-down on USB_DM
|
||||
USB0_OTGSC = USB0_OTGSC_OT;
|
||||
}
|
||||
|
||||
usb_speed_t usb_speed(
|
||||
const usb_device_t* const device
|
||||
) {
|
||||
if( device == usb_device_usb0 ) {
|
||||
switch( USB0_PORTSC1_D & USB0_PORTSC1_D_PSPD_MASK ) {
|
||||
case USB0_PORTSC1_D_PSPD(0):
|
||||
return USB_SPEED_FULL;
|
||||
|
||||
case USB0_PORTSC1_D_PSPD(2):
|
||||
return USB_SPEED_HIGH;
|
||||
|
||||
default:
|
||||
// TODO: What to do/return here? Is this even possible?
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
} else {
|
||||
// TODO: This should not be possible with a more class-like
|
||||
// implementation.
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_clear_status(const uint32_t status) {
|
||||
USB0_USBSTS_D = status;
|
||||
}
|
||||
|
||||
static uint32_t usb_get_status() {
|
||||
// Mask status flags with enabled flag interrupts.
|
||||
const uint32_t status = USB0_USBSTS_D & USB0_USBINTR_D;
|
||||
|
||||
// Clear flags that were just read, leaving alone any flags that
|
||||
// were just set (after the read). It's important to read and
|
||||
// reset flags atomically! :-)
|
||||
usb_clear_status(status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void usb_clear_endpoint_setup_status(const uint32_t endpoint_setup_status) {
|
||||
USB0_ENDPTSETUPSTAT = endpoint_setup_status;
|
||||
}
|
||||
|
||||
static uint32_t usb_get_endpoint_setup_status() {
|
||||
return USB0_ENDPTSETUPSTAT;
|
||||
}
|
||||
|
||||
static void usb_clear_endpoint_complete(const uint32_t endpoint_complete) {
|
||||
USB0_ENDPTCOMPLETE = endpoint_complete;
|
||||
}
|
||||
|
||||
static uint32_t usb_get_endpoint_complete() {
|
||||
return USB0_ENDPTCOMPLETE;
|
||||
}
|
||||
|
||||
static void usb_disable_all_endpoints() {
|
||||
// Endpoint 0 is always enabled. TODO: So why set ENDPTCTRL0?
|
||||
USB0_ENDPTCTRL0 &= ~(USB0_ENDPTCTRL0_RXE | USB0_ENDPTCTRL0_TXE);
|
||||
USB0_ENDPTCTRL1 &= ~(USB0_ENDPTCTRL1_RXE | USB0_ENDPTCTRL1_TXE);
|
||||
USB0_ENDPTCTRL2 &= ~(USB0_ENDPTCTRL2_RXE | USB0_ENDPTCTRL2_TXE);
|
||||
USB0_ENDPTCTRL3 &= ~(USB0_ENDPTCTRL3_RXE | USB0_ENDPTCTRL3_TXE);
|
||||
USB0_ENDPTCTRL4 &= ~(USB0_ENDPTCTRL4_RXE | USB0_ENDPTCTRL4_TXE);
|
||||
USB0_ENDPTCTRL5 &= ~(USB0_ENDPTCTRL5_RXE | USB0_ENDPTCTRL5_TXE);
|
||||
}
|
||||
|
||||
void usb_set_address_immediate(
|
||||
const usb_device_t* const device,
|
||||
const uint_fast8_t address
|
||||
) {
|
||||
if( device == usb_device_usb0 ) {
|
||||
USB0_DEVICEADDR = USB0_DEVICEADDR_USBADR(address);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_set_address_deferred(
|
||||
const usb_device_t* const device,
|
||||
const uint_fast8_t address
|
||||
) {
|
||||
if( device == usb_device_usb0 ) {
|
||||
USB0_DEVICEADDR
|
||||
= USB0_DEVICEADDR_USBADR(address)
|
||||
| USB0_DEVICEADDR_USBADRA
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_reset_all_endpoints() {
|
||||
usb_disable_all_endpoints();
|
||||
usb_clear_all_pending_interrupts();
|
||||
usb_flush_all_primed_endpoints();
|
||||
}
|
||||
|
||||
static void usb_controller_reset() {
|
||||
// TODO: Good to disable some USB interrupts to avoid priming new
|
||||
// new endpoints before the controller is reset?
|
||||
usb_reset_all_endpoints();
|
||||
usb_controller_stop();
|
||||
|
||||
// Reset controller. Resets internal pipelines, timers, counters, state
|
||||
// machines to initial values. Not recommended when device is in attached
|
||||
// state -- effect on attached host is undefined. Detach first by flushing
|
||||
// all primed endpoints and stopping controller.
|
||||
USB0_USBCMD_D = USB0_USBCMD_D_RST;
|
||||
|
||||
while( usb_controller_is_resetting() );
|
||||
}
|
||||
|
||||
static void usb_bus_reset(usb_device_t* const device) {
|
||||
// According to UM10503 v1.4 section 23.10.3 "Bus reset":
|
||||
usb_reset_all_endpoints();
|
||||
usb_set_address_immediate(device, 0);
|
||||
usb_set_configuration(device, 0);
|
||||
|
||||
// TODO: Enable endpoint 0, which might not actually be necessary,
|
||||
// as the datasheet claims it can't be disabled.
|
||||
|
||||
//wait_ms(3);
|
||||
//
|
||||
//if( USB0_PORTSC1 & USB0_PORTSC1_PR ) {
|
||||
// // Port still is in the reset state.
|
||||
//} else {
|
||||
// usb_hardware_reset();
|
||||
//}
|
||||
}
|
||||
|
||||
static void usb_interrupt_enable(
|
||||
usb_device_t* const device
|
||||
) {
|
||||
if( device == usb_device_usb0 ) {
|
||||
nvic_enable_irq(NVIC_USB0_IRQ);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_device_init(
|
||||
const uint_fast8_t device_ordinal,
|
||||
usb_device_t* const device
|
||||
) {
|
||||
if( device_ordinal == 0 ) {
|
||||
usb_device_usb0 = device;
|
||||
|
||||
usb_phy_enable();
|
||||
usb_controller_reset();
|
||||
usb_controller_set_device_mode();
|
||||
|
||||
// Set interrupt threshold interval to 0
|
||||
USB0_USBCMD_D &= ~USB0_USBCMD_D_ITC_MASK;
|
||||
|
||||
// Configure endpoint list address
|
||||
USB0_ENDPOINTLISTADDR = (uint32_t)usb_qh;
|
||||
|
||||
// Enable interrupts
|
||||
USB0_USBINTR_D =
|
||||
USB0_USBINTR_D_UE
|
||||
| USB0_USBINTR_D_UEE
|
||||
| USB0_USBINTR_D_PCE
|
||||
| USB0_USBINTR_D_URE
|
||||
//| USB0_USBINTR_D_SRE
|
||||
| USB0_USBINTR_D_SLE
|
||||
//| USB0_USBINTR_D_NAKE
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_run(
|
||||
usb_device_t* const device
|
||||
) {
|
||||
usb_interrupt_enable(device);
|
||||
usb_controller_run(device);
|
||||
}
|
||||
|
||||
static void copy_setup(usb_setup_t* const dst, const volatile uint8_t* const src) {
|
||||
dst->request_type = src[0];
|
||||
dst->request = src[1];
|
||||
dst->value_l = src[2];
|
||||
dst->value_h = src[3];
|
||||
dst->index_l = src[4];
|
||||
dst->index_h = src[5];
|
||||
dst->length_l = src[6];
|
||||
dst->length_h = src[7];
|
||||
}
|
||||
|
||||
void usb_endpoint_init(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
usb_endpoint_flush(endpoint);
|
||||
|
||||
uint_fast16_t max_packet_size = endpoint->device->descriptor[7];
|
||||
usb_transfer_type_t transfer_type = USB_TRANSFER_TYPE_CONTROL;
|
||||
const uint8_t* const endpoint_descriptor = usb_endpoint_descriptor(endpoint);
|
||||
if( endpoint_descriptor ) {
|
||||
max_packet_size = usb_endpoint_descriptor_max_packet_size(endpoint_descriptor);
|
||||
transfer_type = usb_endpoint_descriptor_transfer_type(endpoint_descriptor);
|
||||
}
|
||||
|
||||
// TODO: There are more capabilities to adjust based on the endpoint
|
||||
// descriptor.
|
||||
usb_queue_head_t* const qh = usb_queue_head(endpoint->address);
|
||||
qh->capabilities
|
||||
= USB_QH_CAPABILITIES_MULT(0)
|
||||
| USB_QH_CAPABILITIES_ZLT
|
||||
| USB_QH_CAPABILITIES_MPL(max_packet_size)
|
||||
| ((transfer_type == USB_TRANSFER_TYPE_CONTROL) ? USB_QH_CAPABILITIES_IOS : 0)
|
||||
;
|
||||
qh->current_dtd_pointer = 0;
|
||||
qh->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
||||
qh->total_bytes
|
||||
= USB_TD_DTD_TOKEN_TOTAL_BYTES(0)
|
||||
| USB_TD_DTD_TOKEN_MULTO(0)
|
||||
;
|
||||
qh->buffer_pointer_page[0] = 0;
|
||||
qh->buffer_pointer_page[1] = 0;
|
||||
qh->buffer_pointer_page[2] = 0;
|
||||
qh->buffer_pointer_page[3] = 0;
|
||||
qh->buffer_pointer_page[4] = 0;
|
||||
|
||||
// This is how we look up an endpoint structure from an endpoint address:
|
||||
qh->_reserved_0 = (uint32_t)endpoint;
|
||||
|
||||
// TODO: Should NAK be enabled? I'm kinda squishy on this...
|
||||
//USB0_ENDPTNAKEN |=
|
||||
// USB0_ENDPTNAKEN_EPRNE(1 << endpoint_out->number);
|
||||
|
||||
usb_endpoint_set_type(endpoint, transfer_type);
|
||||
|
||||
usb_endpoint_enable(endpoint);
|
||||
}
|
||||
|
||||
static void usb_check_for_setup_events() {
|
||||
const uint32_t endptsetupstat = usb_get_endpoint_setup_status();
|
||||
if( endptsetupstat ) {
|
||||
for( uint_fast8_t i=0; i<6; i++ ) {
|
||||
const uint32_t endptsetupstat_bit = USB0_ENDPTSETUPSTAT_ENDPTSETUPSTAT(1 << i);
|
||||
if( endptsetupstat & endptsetupstat_bit ) {
|
||||
usb_endpoint_t* const endpoint =
|
||||
usb_endpoint_from_address(
|
||||
usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i)
|
||||
);
|
||||
if( endpoint && endpoint->setup_complete ) {
|
||||
copy_setup(&endpoint->setup, usb_queue_head(endpoint->address)->setup);
|
||||
// TODO: Clean up this duplicated effort by providing
|
||||
// a cleaner way to get the SETUP data.
|
||||
copy_setup(&endpoint->in->setup, usb_queue_head(endpoint->address)->setup);
|
||||
usb_clear_endpoint_setup_status(endptsetupstat_bit);
|
||||
endpoint->setup_complete(endpoint);
|
||||
} else {
|
||||
usb_clear_endpoint_setup_status(endptsetupstat_bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_check_for_transfer_events() {
|
||||
const uint32_t endptcomplete = usb_get_endpoint_complete();
|
||||
if( endptcomplete ) {
|
||||
for( uint_fast8_t i=0; i<6; i++ ) {
|
||||
|
||||
const uint32_t endptcomplete_out_bit = USB0_ENDPTCOMPLETE_ERCE(1 << i);
|
||||
if( endptcomplete & endptcomplete_out_bit ) {
|
||||
usb_clear_endpoint_complete(endptcomplete_out_bit);
|
||||
usb_endpoint_t* const endpoint =
|
||||
usb_endpoint_from_address(
|
||||
usb_endpoint_address(USB_TRANSFER_DIRECTION_OUT, i)
|
||||
);
|
||||
if( endpoint && endpoint->transfer_complete ) {
|
||||
endpoint->transfer_complete(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t endptcomplete_in_bit = USB0_ENDPTCOMPLETE_ETCE(1 << i);
|
||||
if( endptcomplete & endptcomplete_in_bit ) {
|
||||
usb_clear_endpoint_complete(endptcomplete_in_bit);
|
||||
usb_endpoint_t* const endpoint =
|
||||
usb_endpoint_from_address(
|
||||
usb_endpoint_address(USB_TRANSFER_DIRECTION_IN, i)
|
||||
);
|
||||
if( endpoint && endpoint->transfer_complete ) {
|
||||
endpoint->transfer_complete(endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void usb0_isr() {
|
||||
const uint32_t status = usb_get_status();
|
||||
|
||||
if( status == 0 ) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if( status & USB0_USBSTS_D_UI ) {
|
||||
// USB:
|
||||
// - Completed transaction transfer descriptor has IOC set.
|
||||
// - Short packet detected.
|
||||
// - SETUP packet received.
|
||||
|
||||
usb_check_for_setup_events();
|
||||
usb_check_for_transfer_events();
|
||||
|
||||
// TODO: Reset ignored ENDPTSETUPSTAT and ENDPTCOMPLETE flags?
|
||||
}
|
||||
|
||||
if( status & USB0_USBSTS_D_SRI ) {
|
||||
// Start Of Frame received.
|
||||
}
|
||||
|
||||
if( status & USB0_USBSTS_D_PCI ) {
|
||||
// Port change detect:
|
||||
// Port controller entered full- or high-speed operational state.
|
||||
}
|
||||
|
||||
if( status & USB0_USBSTS_D_SLI ) {
|
||||
// Device controller suspend.
|
||||
}
|
||||
|
||||
if( status & USB0_USBSTS_D_URI ) {
|
||||
// USB reset received.
|
||||
usb_bus_reset(usb_device_usb0);
|
||||
}
|
||||
|
||||
if( status & USB0_USBSTS_D_UEI ) {
|
||||
// USB error:
|
||||
// Completion of a USB transaction resulted in an error condition.
|
||||
// Set along with USBINT if the TD on which the error interrupt
|
||||
// occurred also had its interrupt on complete (IOC) bit set.
|
||||
// The device controller detects resume signalling only.
|
||||
}
|
||||
|
||||
if( status & USB0_USBSTS_D_NAKI ) {
|
||||
// Both the TX/RX endpoint NAK bit and corresponding TX/RX endpoint
|
||||
// NAK enable bit are set.
|
||||
}
|
||||
}
|
105
Software/portapack-mayhem/hackrf/firmware/common/usb.h
Normal file
105
Software/portapack-mayhem/hackrf/firmware/common/usb.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
// TODO: Refactor to support high performance operations without having to
|
||||
// expose usb_transfer_descriptor_t. Or usb_endpoint_prime(). Or, or, or...
|
||||
#include <libopencm3/lpc43xx/usb.h>
|
||||
|
||||
#include "usb_type.h"
|
||||
|
||||
void usb_peripheral_reset();
|
||||
void usb_phy_enable();
|
||||
|
||||
void usb_device_init(
|
||||
const uint_fast8_t device_ordinal,
|
||||
usb_device_t* const device
|
||||
);
|
||||
|
||||
void usb_run(
|
||||
usb_device_t* const device
|
||||
);
|
||||
|
||||
void usb_run_tasks(
|
||||
const usb_device_t* const device
|
||||
);
|
||||
|
||||
usb_speed_t usb_speed(
|
||||
const usb_device_t* const device
|
||||
);
|
||||
|
||||
void usb_set_address_immediate(
|
||||
const usb_device_t* const device,
|
||||
const uint_fast8_t address
|
||||
);
|
||||
|
||||
void usb_set_address_deferred(
|
||||
const usb_device_t* const device,
|
||||
const uint_fast8_t address
|
||||
);
|
||||
|
||||
usb_endpoint_t* usb_endpoint_from_address(
|
||||
const uint_fast8_t endpoint_address
|
||||
);
|
||||
|
||||
void usb_endpoint_init(
|
||||
const usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
void usb_endpoint_stall(
|
||||
const usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
void usb_endpoint_disable(
|
||||
const usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
void usb_endpoint_reset_data_toggle(
|
||||
const usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
void usb_endpoint_flush(
|
||||
const usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
bool usb_endpoint_is_ready(
|
||||
const usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
void usb_endpoint_prime(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
usb_transfer_descriptor_t* const first_td
|
||||
);
|
||||
|
||||
void usb_endpoint_schedule_wait(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
usb_transfer_descriptor_t* const td
|
||||
);
|
||||
|
||||
void usb_endpoint_schedule_append(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
usb_transfer_descriptor_t* const tail_td,
|
||||
usb_transfer_descriptor_t* const new_td
|
||||
);
|
||||
|
||||
#endif//__USB_H__
|
227
Software/portapack-mayhem/hackrf/firmware/common/usb_queue.c
Normal file
227
Software/portapack-mayhem/hackrf/firmware/common/usb_queue.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone
|
||||
* Copyright 2013 Ben Gamari
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libopencm3/cm3/cortex.h>
|
||||
#include <libopencm3/cm3/sync.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "usb_queue.h"
|
||||
|
||||
usb_queue_t* endpoint_queues[12] = {};
|
||||
|
||||
#define USB_ENDPOINT_INDEX(endpoint_address) (((endpoint_address & 0xF) * 2) + ((endpoint_address >> 7) & 1))
|
||||
|
||||
static usb_queue_t* endpoint_queue(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
uint32_t index = USB_ENDPOINT_INDEX(endpoint->address);
|
||||
if (endpoint_queues[index] == NULL) while (1);
|
||||
return endpoint_queues[index];
|
||||
}
|
||||
|
||||
void usb_queue_init(
|
||||
usb_queue_t* const queue
|
||||
) {
|
||||
uint32_t index = USB_ENDPOINT_INDEX(queue->endpoint->address);
|
||||
if (endpoint_queues[index] != NULL) while (1);
|
||||
endpoint_queues[index] = queue;
|
||||
|
||||
usb_transfer_t* t = queue->free_transfers;
|
||||
for (unsigned int i=0; i < queue->pool_size - 1; i++, t++) {
|
||||
t->next = t+1;
|
||||
t->queue = queue;
|
||||
}
|
||||
t->next = NULL;
|
||||
t->queue = queue;
|
||||
}
|
||||
|
||||
/* Allocate a transfer */
|
||||
static usb_transfer_t* allocate_transfer(
|
||||
usb_queue_t* const queue
|
||||
) {
|
||||
bool aborted;
|
||||
usb_transfer_t* transfer;
|
||||
if (queue->free_transfers == NULL)
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
transfer = (void *) __ldrex((uint32_t *) &queue->free_transfers);
|
||||
aborted = __strex((uint32_t) transfer->next, (uint32_t *) &queue->free_transfers);
|
||||
} while (aborted);
|
||||
transfer->next = NULL;
|
||||
return transfer;
|
||||
}
|
||||
|
||||
/* Place a transfer in the free list */
|
||||
static void free_transfer(usb_transfer_t* const transfer)
|
||||
{
|
||||
usb_queue_t* const queue = transfer->queue;
|
||||
bool aborted;
|
||||
do {
|
||||
transfer->next = (void *) __ldrex((uint32_t *) &queue->free_transfers);
|
||||
aborted = __strex((uint32_t) transfer, (uint32_t *) &queue->free_transfers);
|
||||
} while (aborted);
|
||||
}
|
||||
|
||||
/* Add a transfer to the end of an endpoint's queue. Returns the old
|
||||
* tail or NULL is the queue was empty
|
||||
*/
|
||||
static usb_transfer_t* endpoint_queue_transfer(
|
||||
usb_transfer_t* const transfer
|
||||
) {
|
||||
usb_queue_t* const queue = transfer->queue;
|
||||
transfer->next = NULL;
|
||||
if (queue->active != NULL) {
|
||||
usb_transfer_t* t = queue->active;
|
||||
while (t->next != NULL) t = t->next;
|
||||
t->next = transfer;
|
||||
return t;
|
||||
} else {
|
||||
queue->active = transfer;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_queue_flush_queue(usb_queue_t* const queue)
|
||||
{
|
||||
cm_disable_interrupts();
|
||||
while (queue->active) {
|
||||
usb_transfer_t* transfer = queue->active;
|
||||
queue->active = transfer->next;
|
||||
free_transfer(transfer);
|
||||
}
|
||||
cm_enable_interrupts();
|
||||
}
|
||||
|
||||
void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint)
|
||||
{
|
||||
usb_queue_flush_queue(endpoint_queue(endpoint));
|
||||
}
|
||||
|
||||
int usb_transfer_schedule(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
void* const data,
|
||||
const uint32_t maximum_length,
|
||||
const transfer_completion_cb completion_cb,
|
||||
void* const user_data
|
||||
) {
|
||||
usb_queue_t* const queue = endpoint_queue(endpoint);
|
||||
usb_transfer_t* const transfer = allocate_transfer(queue);
|
||||
if (transfer == NULL) return -1;
|
||||
usb_transfer_descriptor_t* const td = &transfer->td;
|
||||
|
||||
// Configure the transfer descriptor
|
||||
td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE;
|
||||
td->total_bytes =
|
||||
USB_TD_DTD_TOKEN_TOTAL_BYTES(maximum_length)
|
||||
| USB_TD_DTD_TOKEN_IOC
|
||||
| USB_TD_DTD_TOKEN_MULTO(0)
|
||||
| USB_TD_DTD_TOKEN_STATUS_ACTIVE
|
||||
;
|
||||
td->buffer_pointer_page[0] = (uint32_t)data;
|
||||
td->buffer_pointer_page[1] = ((uint32_t)data + 0x1000) & 0xfffff000;
|
||||
td->buffer_pointer_page[2] = ((uint32_t)data + 0x2000) & 0xfffff000;
|
||||
td->buffer_pointer_page[3] = ((uint32_t)data + 0x3000) & 0xfffff000;
|
||||
td->buffer_pointer_page[4] = ((uint32_t)data + 0x4000) & 0xfffff000;
|
||||
|
||||
// Fill in transfer fields
|
||||
transfer->maximum_length = maximum_length;
|
||||
transfer->completion_cb = completion_cb;
|
||||
transfer->user_data = user_data;
|
||||
|
||||
cm_disable_interrupts();
|
||||
usb_transfer_t* tail = endpoint_queue_transfer(transfer);
|
||||
if (tail == NULL) {
|
||||
// The queue is currently empty, we need to re-prime
|
||||
usb_endpoint_schedule_wait(queue->endpoint, &transfer->td);
|
||||
} else {
|
||||
// The queue is currently running, try to append
|
||||
usb_endpoint_schedule_append(queue->endpoint, &tail->td, &transfer->td);
|
||||
}
|
||||
cm_enable_interrupts();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_transfer_schedule_block(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
void* const data,
|
||||
const uint32_t maximum_length,
|
||||
const transfer_completion_cb completion_cb,
|
||||
void* const user_data
|
||||
) {
|
||||
int ret;
|
||||
do {
|
||||
ret = usb_transfer_schedule(endpoint, data, maximum_length,
|
||||
completion_cb, user_data);
|
||||
} while (ret == -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_transfer_schedule_ack(
|
||||
const usb_endpoint_t* const endpoint
|
||||
) {
|
||||
return usb_transfer_schedule_block(endpoint, 0, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Called when an endpoint might have completed a transfer */
|
||||
void usb_queue_transfer_complete(usb_endpoint_t* const endpoint)
|
||||
{
|
||||
usb_queue_t* const queue = endpoint_queue(endpoint);
|
||||
if (queue == NULL) while(1); // Uh oh
|
||||
usb_transfer_t* transfer = queue->active;
|
||||
|
||||
while (transfer != NULL) {
|
||||
uint8_t status = transfer->td.total_bytes;
|
||||
|
||||
// Check for failures
|
||||
if ( status & USB_TD_DTD_TOKEN_STATUS_HALTED
|
||||
|| status & USB_TD_DTD_TOKEN_STATUS_BUFFER_ERROR
|
||||
|| status & USB_TD_DTD_TOKEN_STATUS_TRANSACTION_ERROR) {
|
||||
// TODO: Uh oh, do something useful here
|
||||
while (1);
|
||||
}
|
||||
|
||||
// Still not finished
|
||||
if (status & USB_TD_DTD_TOKEN_STATUS_ACTIVE)
|
||||
break;
|
||||
|
||||
// Advance the head. We need to do this before invoking the completion
|
||||
// callback as it might attempt to schedule a new transfer
|
||||
queue->active = transfer->next;
|
||||
usb_transfer_t* next = transfer->next;
|
||||
|
||||
// Invoke completion callback
|
||||
unsigned int total_bytes = (transfer->td.total_bytes & USB_TD_DTD_TOKEN_TOTAL_BYTES_MASK) >> USB_TD_DTD_TOKEN_TOTAL_BYTES_SHIFT;
|
||||
unsigned int transferred = transfer->maximum_length - total_bytes;
|
||||
if (transfer->completion_cb)
|
||||
transfer->completion_cb(transfer->user_data, transferred);
|
||||
|
||||
// Advance head and free transfer
|
||||
free_transfer(transfer);
|
||||
transfer = next;
|
||||
}
|
||||
}
|
92
Software/portapack-mayhem/hackrf/firmware/common/usb_queue.h
Normal file
92
Software/portapack-mayhem/hackrf/firmware/common/usb_queue.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone
|
||||
* Copyright 2013 Ben Gamari
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __USB_QUEUE_H__
|
||||
#define __USB_QUEUE_H__
|
||||
|
||||
#include <libopencm3/lpc43xx/usb.h>
|
||||
|
||||
#include "usb_type.h"
|
||||
|
||||
typedef struct _usb_transfer_t usb_transfer_t;
|
||||
typedef struct _usb_queue_t usb_queue_t;
|
||||
typedef void (*transfer_completion_cb)(void*, unsigned int);
|
||||
|
||||
// This is an opaque datatype. Thou shall not touch these members.
|
||||
struct _usb_transfer_t {
|
||||
struct _usb_transfer_t* next;
|
||||
usb_transfer_descriptor_t td ATTR_ALIGNED(64);
|
||||
unsigned int maximum_length;
|
||||
struct _usb_queue_t* queue;
|
||||
transfer_completion_cb completion_cb;
|
||||
void* user_data;
|
||||
};
|
||||
|
||||
// This is an opaque datatype. Thou shall not touch these members.
|
||||
struct _usb_queue_t {
|
||||
struct usb_endpoint_t* endpoint;
|
||||
const unsigned int pool_size;
|
||||
usb_transfer_t* volatile free_transfers;
|
||||
usb_transfer_t* volatile active;
|
||||
};
|
||||
|
||||
#define USB_DECLARE_QUEUE(endpoint_name) \
|
||||
struct _usb_queue_t endpoint_name##_queue;
|
||||
#define USB_DEFINE_QUEUE(endpoint_name, _pool_size) \
|
||||
struct _usb_transfer_t endpoint_name##_transfers[_pool_size]; \
|
||||
struct _usb_queue_t endpoint_name##_queue = { \
|
||||
.endpoint = &endpoint_name, \
|
||||
.free_transfers = endpoint_name##_transfers, \
|
||||
.pool_size = _pool_size \
|
||||
};
|
||||
|
||||
void usb_queue_flush_endpoint(const usb_endpoint_t* const endpoint);
|
||||
|
||||
int usb_transfer_schedule(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
void* const data,
|
||||
const uint32_t maximum_length,
|
||||
const transfer_completion_cb completion_cb,
|
||||
void* const user_data
|
||||
);
|
||||
|
||||
int usb_transfer_schedule_block(
|
||||
const usb_endpoint_t* const endpoint,
|
||||
void* const data,
|
||||
const uint32_t maximum_length,
|
||||
const transfer_completion_cb completion_cb,
|
||||
void* const user_data
|
||||
);
|
||||
|
||||
int usb_transfer_schedule_ack(
|
||||
const usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
void usb_queue_init(
|
||||
usb_queue_t* const queue
|
||||
);
|
||||
|
||||
void usb_queue_transfer_complete(
|
||||
usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
#endif//__USB_QUEUE_H__
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "usb.h"
|
||||
#include "usb_request.h"
|
||||
#include "usb_queue.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
static void usb_request(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage
|
||||
) {
|
||||
usb_request_status_t status = USB_REQUEST_STATUS_STALL;
|
||||
usb_request_handler_fn handler = 0;
|
||||
|
||||
switch( endpoint->setup.request_type & USB_SETUP_REQUEST_TYPE_mask ) {
|
||||
case USB_SETUP_REQUEST_TYPE_STANDARD:
|
||||
handler = usb_request_handlers.standard;
|
||||
break;
|
||||
|
||||
case USB_SETUP_REQUEST_TYPE_CLASS:
|
||||
handler = usb_request_handlers.class;
|
||||
break;
|
||||
|
||||
case USB_SETUP_REQUEST_TYPE_VENDOR:
|
||||
handler = usb_request_handlers.vendor;
|
||||
break;
|
||||
|
||||
case USB_SETUP_REQUEST_TYPE_RESERVED:
|
||||
handler = usb_request_handlers.reserved;
|
||||
break;
|
||||
}
|
||||
|
||||
if( handler ) {
|
||||
status = handler(endpoint, stage);
|
||||
}
|
||||
|
||||
if( status != USB_REQUEST_STATUS_OK ) {
|
||||
// USB 2.0 section 9.2.7 "Request Error"
|
||||
usb_endpoint_stall(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_setup_complete(
|
||||
usb_endpoint_t* const endpoint
|
||||
) {
|
||||
usb_request(endpoint, USB_TRANSFER_STAGE_SETUP);
|
||||
}
|
||||
|
||||
void usb_control_out_complete(
|
||||
usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const bool device_to_host =
|
||||
endpoint->setup.request_type >> USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_shift;
|
||||
if( device_to_host ) {
|
||||
usb_request(endpoint, USB_TRANSFER_STAGE_STATUS);
|
||||
} else {
|
||||
usb_request(endpoint, USB_TRANSFER_STAGE_DATA);
|
||||
}
|
||||
usb_queue_transfer_complete(endpoint);
|
||||
}
|
||||
|
||||
void usb_control_in_complete(
|
||||
usb_endpoint_t* const endpoint
|
||||
) {
|
||||
const bool device_to_host =
|
||||
endpoint->setup.request_type >> USB_SETUP_REQUEST_TYPE_DATA_TRANSFER_DIRECTION_shift;
|
||||
if( device_to_host ) {
|
||||
usb_request(endpoint, USB_TRANSFER_STAGE_DATA);
|
||||
} else {
|
||||
usb_request(endpoint, USB_TRANSFER_STAGE_STATUS);
|
||||
}
|
||||
usb_queue_transfer_complete(endpoint);
|
||||
}
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __USB_REQUEST_H__
|
||||
#define __USB_REQUEST_H__
|
||||
|
||||
#include "usb_type.h"
|
||||
|
||||
typedef enum {
|
||||
USB_RESPONSE_NONE,
|
||||
USB_RESPONSE_IN,
|
||||
USB_RESPONSE_OUT,
|
||||
USB_RESPONSE_STALL,
|
||||
} usb_endpoint_type_t;
|
||||
|
||||
typedef enum {
|
||||
USB_TRANSFER_STAGE_SETUP,
|
||||
USB_TRANSFER_STAGE_DATA,
|
||||
USB_TRANSFER_STAGE_STATUS,
|
||||
} usb_transfer_stage_t;
|
||||
|
||||
typedef enum {
|
||||
USB_REQUEST_STATUS_OK = 0,
|
||||
USB_REQUEST_STATUS_STALL = 1,
|
||||
} usb_request_status_t;
|
||||
|
||||
typedef usb_request_status_t (*usb_request_handler_fn)(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage
|
||||
);
|
||||
|
||||
typedef struct {
|
||||
usb_request_handler_fn standard;
|
||||
usb_request_handler_fn class;
|
||||
usb_request_handler_fn vendor;
|
||||
usb_request_handler_fn reserved;
|
||||
} usb_request_handlers_t;
|
||||
|
||||
extern const usb_request_handlers_t usb_request_handlers;
|
||||
|
||||
void usb_setup_complete(
|
||||
usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
void usb_control_in_complete(
|
||||
usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
void usb_control_out_complete(
|
||||
usb_endpoint_t* const endpoint
|
||||
);
|
||||
|
||||
#endif//__USB_REQUEST_H__
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user