Merge branch 'abstract_buses' of https://github.com/jboone/hackrf into jboone-abstract_buses

This commit is contained in:
Dominic Spill
2015-12-18 12:24:43 +00:00
66 changed files with 2604 additions and 1723 deletions

View File

@ -19,13 +19,8 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h" #include "hackrf_core.h"
uint32_t boot0, boot1, boot2, boot3;
int main(void) int main(void)
{ {
int i; int i;
@ -34,18 +29,20 @@ int main(void)
/* enable all power supplies */ /* enable all power supplies */
enable_1v8_power(); enable_1v8_power();
/* Blink LED1/2/3 on the board and Read BOOT0/1/2/3 pins. */ /* Blink LED1/2/3 on the board. */
while (1) while (1)
{ {
boot0 = BOOT0_STATE; led_on(LED1);
boot1 = BOOT1_STATE; led_on(LED2);
boot2 = BOOT2_STATE; led_on(LED3);
boot3 = BOOT3_STATE;
gpio_set(PORT_LED1_3, (PIN_LED1|PIN_LED2|PIN_LED3)); /* LEDs on */
for (i = 0; i < 2000000; i++) /* Wait a bit. */ for (i = 0; i < 2000000; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
gpio_clear(PORT_LED1_3, (PIN_LED1|PIN_LED2|PIN_LED3)); /* LED off */
led_off(LED1);
led_off(LED2);
led_off(LED3);
for (i = 0; i < 2000000; i++) /* Wait a bit. */ for (i = 0; i < 2000000; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
} }

View File

@ -22,7 +22,6 @@
#include "cpld_jtag.h" #include "cpld_jtag.h"
#include "hackrf_core.h" #include "hackrf_core.h"
#include "xapp058/micro.h" #include "xapp058/micro.h"
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h> #include <libopencm3/lpc43xx/scu.h>
#include <stdint.h> #include <stdint.h>
@ -30,47 +29,45 @@ static refill_buffer_cb refill_buffer;
static uint32_t xsvf_buffer_len, xsvf_pos; static uint32_t xsvf_buffer_len, xsvf_pos;
static unsigned char* xsvf_buffer; static unsigned char* xsvf_buffer;
void cpld_jtag_setup(void) { void cpld_jtag_setup(jtag_t* const jtag) {
scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
/* TDO is an input */ gpio_input(jtag->gpio->gpio_tdo);
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO; gpio_output(jtag->gpio->gpio_tck);
gpio_output(jtag->gpio->gpio_tms);
/* the rest are outputs */ gpio_output(jtag->gpio->gpio_tdi);
GPIO_DIR(PORT_CPLD_TCK) |= PIN_CPLD_TCK;
GPIO_DIR(PORT_CPLD_TMS) |= PIN_CPLD_TMS;
GPIO_DIR(PORT_CPLD_TDI) |= PIN_CPLD_TDI;
} }
/* set pins as inputs so we don't interfere with an external JTAG device */ /* set pins as inputs so we don't interfere with an external JTAG device */
void cpld_jtag_release(void) { void cpld_jtag_release(jtag_t* const jtag) {
scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO; gpio_input(jtag->gpio->gpio_tdo);
GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK; gpio_input(jtag->gpio->gpio_tck);
GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS; gpio_input(jtag->gpio->gpio_tms);
GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI; gpio_input(jtag->gpio->gpio_tdi);
} }
/* return 0 if success else return error code see xsvfExecute() */ /* return 0 if success else return error code see xsvfExecute() */
int cpld_jtag_program( int cpld_jtag_program(
jtag_t* const jtag,
const uint32_t buffer_length, const uint32_t buffer_length,
unsigned char* const buffer, unsigned char* const buffer,
refill_buffer_cb refill refill_buffer_cb refill
) { ) {
int error; int error;
cpld_jtag_setup(); cpld_jtag_setup(jtag);
xsvf_buffer = buffer; xsvf_buffer = buffer;
xsvf_buffer_len = buffer_length; xsvf_buffer_len = buffer_length;
refill_buffer = refill; refill_buffer = refill;
error = xsvfExecute(); error = xsvfExecute(jtag->gpio);
cpld_jtag_release(); cpld_jtag_release(jtag);
return error; return error;
} }

View File

@ -24,9 +24,22 @@
#include <stdint.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;
} jtag_gpio_t;
typedef struct jtag_t {
jtag_gpio_t* const gpio;
} jtag_t;
typedef void (*refill_buffer_cb)(void); typedef void (*refill_buffer_cb)(void);
void cpld_jtag_release(void); void cpld_jtag_release(jtag_t* const jtag);
/* Return 0 if success else return error code see xsvfExecute() see micro.h. /* Return 0 if success else return error code see xsvfExecute() see micro.h.
* *
@ -34,6 +47,7 @@ void cpld_jtag_release(void);
* contents of the buffer has been streamed to the CPLD the given * contents of the buffer has been streamed to the CPLD the given
* refill_buffer callback will be called. */ * refill_buffer callback will be called. */
int cpld_jtag_program( int cpld_jtag_program(
jtag_t* const jtag,
const uint32_t buffer_length, const uint32_t buffer_length,
unsigned char* const buffer, unsigned char* const buffer,
refill_buffer_cb refill refill_buffer_cb refill

38
firmware/common/gpio.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GPIO_H__
#define __GPIO_H__
#include <stdbool.h>
typedef const struct gpio_t* gpio_t;
void gpio_init();
void gpio_set(gpio_t gpio);
void gpio_clear(gpio_t gpio);
void gpio_toggle(gpio_t gpio);
void gpio_output(gpio_t gpio);
void gpio_input(gpio_t gpio);
void gpio_write(gpio_t gpio, const bool value);
bool gpio_read(gpio_t gpio);
#endif/*__GPIO_H__*/

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "gpio_lpc.h"
#include <stddef.h>
void gpio_init() {
for(size_t i=0; i<8; i++) {
GPIO_LPC_PORT(i)->dir = 0;
}
}
void gpio_set(gpio_t gpio) {
gpio->port->set = gpio->mask;
}
void gpio_clear(gpio_t gpio) {
gpio->port->clr = gpio->mask;
}
void gpio_toggle(gpio_t gpio) {
gpio->port->not = gpio->mask;
}
void gpio_output(gpio_t gpio) {
gpio->port->dir |= gpio->mask;
}
void gpio_input(gpio_t gpio) {
gpio->port->dir &= ~gpio->mask;
}
void gpio_write(gpio_t gpio, const bool value) {
*gpio->gpio_w = value;
}
bool gpio_read(gpio_t gpio) {
return *gpio->gpio_w;
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GPIO_LPC_H__
#define __GPIO_LPC_H__
#include <stdint.h>
#include "gpio.h"
/* NOTE: libopencm3 constants and functions not used here due to naming
* conflicts. I'd recommend changes to libopencm3 design to separate
* register #defines and API declarations into separate header files.
*/
typedef struct gpio_port_t {
volatile uint32_t dir; /* +0x000 */
uint32_t _reserved0[31];
volatile uint32_t mask; /* +0x080 */
uint32_t _reserved1[31];
volatile uint32_t pin; /* +0x100 */
uint32_t _reserved2[31];
volatile uint32_t mpin; /* +0x180 */
uint32_t _reserved3[31];
volatile uint32_t set; /* +0x200 */
uint32_t _reserved4[31];
volatile uint32_t clr; /* +0x280 */
uint32_t _reserved5[31];
volatile uint32_t not; /* +0x300 */
} gpio_port_t;
struct gpio_t {
const uint32_t mask;
gpio_port_t* const port;
volatile uint32_t* const gpio_w;
};
#define GPIO_LPC_BASE (0x400f4000)
#define GPIO_LPC_B_OFFSET (0x0)
#define GPIO_LPC_W_OFFSET (0x1000)
#define GPIO_LPC_PORT_OFFSET (0x2000)
#define GPIO_LPC_PORT(_n) ((gpio_port_t*)((GPIO_LPC_BASE + GPIO_LPC_PORT_OFFSET) + (_n) * 4))
#define GPIO_LPC_W(_port_num, _pin_num) (volatile uint32_t*)((GPIO_LPC_BASE + GPIO_LPC_W_OFFSET) + ((_port_num) * 0x80) + ((_pin_num) * 4))
#define GPIO(_port_num, _pin_num) { \
.mask = (1UL << (_pin_num)), \
.port = GPIO_LPC_PORT(_port_num), \
.gpio_w = GPIO_LPC_W(_port_num, _pin_num), \
}
#endif/*__GPIO_LPC_H__*/

View File

@ -23,18 +23,295 @@
#include "hackrf_core.h" #include "hackrf_core.h"
#include "si5351c.h" #include "si5351c.h"
#include "spi_ssp.h"
#include "max2837.h" #include "max2837.h"
#include "max2837_target.h"
#include "max5864.h"
#include "max5864_target.h"
#include "rffc5071.h" #include "rffc5071.h"
#include "sgpio.h" #include "rffc5071_spi.h"
#include "rf_path.h" #include "w25q80bv.h"
#include <libopencm3/lpc43xx/i2c.h> #include "w25q80bv_target.h"
#include "i2c_bus.h"
#include "i2c_lpc.h"
#include <libopencm3/lpc43xx/cgu.h> #include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h> #include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/ssp.h> #include <libopencm3/lpc43xx/ssp.h>
#include "gpio_lpc.h"
/* TODO: Consolidate ARRAY_SIZE declarations */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define WAIT_CPU_CLOCK_INIT_DELAY (10000) #define WAIT_CPU_CLOCK_INIT_DELAY (10000)
/* GPIO Output PinMux */
static struct gpio_t gpio_led[3] = {
GPIO(2, 1),
GPIO(2, 2),
GPIO(2, 8)
};
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);
#ifdef JELLYBEAN
static struct gpio_t gpio_max2837_rxhp = GPIO(2, 0);
static struct gpio_t gpio_max2837_b1 = GPIO(2, 9);
static struct gpio_t gpio_max2837_b2 = GPIO(2, 10);
static struct gpio_t gpio_max2837_b3 = GPIO(2, 11);
static struct gpio_t gpio_max2837_b4 = GPIO(2, 12);
static struct gpio_t gpio_max2837_b5 = GPIO(2, 13);
static struct gpio_t gpio_max2837_b6 = GPIO(2, 14);
static struct gpio_t gpio_max2837_b7 = GPIO(2, 15);
#endif
/* MAX5864 SPI chip select (AD_CS) GPIO PinMux */
static struct gpio_t gpio_max5864_select = GPIO(2, 7);
/* RFFC5071 GPIO serial interface PinMux */
#ifdef JELLYBEAN
static struct gpio_t gpio_rffc5072_select = GPIO(3, 8);
static struct gpio_t gpio_rffc5072_clock = GPIO(3, 9);
static struct gpio_t gpio_rffc5072_data = GPIO(3, 10);
static struct gpio_t gpio_rffc5072_reset = GPIO(3, 11);
#endif
#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
/* RF LDO control */
#ifdef JAWBREAKER
static struct gpio_t gpio_rf_ldo_enable = GPIO(2, 9);
#endif
/* RF supply (VAA) control */
#ifdef HACKRF_ONE
static struct gpio_t gpio_vaa_disable = 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
#if 0
/* GPIO Input */
static struct gpio_t gpio_boot[] = {
GPIO(0, 8),
GPIO(0, 9),
GPIO(5, 7),
GPIO(1, 10),
};
#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);
#ifdef HACKRF_ONE
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
static struct gpio_t gpio_rx_decimation[3] = {
GPIO(5, 12),
GPIO(5, 13),
GPIO(5, 14),
};
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,
#ifdef JELLYBEAN
.gpio_rxhp = &gpio_max2837_rxhp,
.gpio_b1 = &gpio_max2837_b1,
.gpio_b2 = &gpio_max2837_b2,
.gpio_b3 = &gpio_max2837_b3,
.gpio_b4 = &gpio_max2837_b4,
.gpio_b5 = &gpio_max2837_b5,
.gpio_b6 = &gpio_max2837_b6,
.gpio_b7 = &gpio_max2837_b7,
#endif
.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 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,
};
rffc5071_driver_t rffc5072 = {
.bus = &spi_bus_rffc5071,
.gpio_reset = &gpio_rffc5072_reset,
};
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_rx_decimation = {
&gpio_rx_decimation[0],
&gpio_rx_decimation[1],
&gpio_rx_decimation[2],
},
.slice_mode_multislice = true,
};
rf_path_t rf_path = {
.switchctrl = 0,
.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,
};
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,
};
jtag_t jtag_cpld = {
.gpio = &jtag_gpio_cpld,
};
void delay(uint32_t duration) void delay(uint32_t duration)
{ {
uint32_t i; uint32_t i;
@ -118,9 +395,9 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
/* Can we enable integer mode ? */ /* Can we enable integer mode ? */
if (a & 0x1 || b) if (a & 0x1 || b)
si5351c_set_int_mode(0, 0); si5351c_set_int_mode(&clock_gen, 0, 0);
else else
si5351c_set_int_mode(0, 1); si5351c_set_int_mode(&clock_gen, 0, 1);
/* Final MS values */ /* Final MS values */
MSx_P1 = 128*a + (128 * b/c) - 512; MSx_P1 = 128*a + (128 * b/c) - 512;
@ -128,13 +405,13 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
MSx_P3 = c; MSx_P3 = c;
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(0, MSx_P1, MSx_P2, MSx_P3, 1); si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(1, 0, 0, 0, 0);//p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0);//p1 doesn't matter
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(2, 0, 0, 0, 0);//p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0);//p1 doesn't matter
return true; return true;
} }
@ -174,13 +451,13 @@ bool sample_rate_set(const uint32_t sample_rate_hz) {
* values are irrelevant. */ * values are irrelevant. */
/* MS0/CLK1 is the source for the MAX5864 codec. */ /* MS0/CLK1 is the source for the MAX5864 codec. */
si5351c_configure_multisynth(1, 4608, 0, 1, r_div_sample); si5351c_configure_multisynth(&clock_gen, 1, 4608, 0, 1, r_div_sample);
/* MS0/CLK2 is the source for the CPLD codec clock (same as CLK1). */ /* MS0/CLK2 is the source for the CPLD codec clock (same as CLK1). */
si5351c_configure_multisynth(2, 4608, 0, 1, r_div_sample); si5351c_configure_multisynth(&clock_gen, 2, 4608, 0, 1, r_div_sample);
/* MS0/CLK3 is the source for the SGPIO clock. */ /* MS0/CLK3 is the source for the SGPIO clock. */
si5351c_configure_multisynth(3, 4608, 0, 1, r_div_sgpio); si5351c_configure_multisynth(&clock_gen, 3, 4608, 0, 1, r_div_sgpio);
return true; return true;
#endif #endif
@ -237,20 +514,20 @@ bool sample_rate_set(const uint32_t sample_rate_hz) {
} }
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(0, p1, p2, p3, 1); si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */ /* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(1, p1, 0, 1, 0);//p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 1, p1, 0, 1, 0);//p1 doesn't matter
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */ /* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(2, p1, 0, 1, 0);//p1 doesn't matter si5351c_configure_multisynth(&clock_gen, 2, p1, 0, 1, 0);//p1 doesn't matter
return true; return true;
#endif #endif
} }
bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) { bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz) {
return max2837_set_lpf_bandwidth(bandwidth_hz); return max2837_set_lpf_bandwidth(&max2837, bandwidth_hz);
} }
/* clock startup for Jellybean with Lemondrop attached /* clock startup for Jellybean with Lemondrop attached
@ -264,15 +541,15 @@ void cpu_clock_init(void)
/* use IRC as clock source for APB3 */ /* use IRC as clock source for APB3 */
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC); CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC);
i2c0_init(15); i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_slow_clock);
si5351c_disable_all_outputs(); si5351c_disable_all_outputs(&clock_gen);
si5351c_disable_oeb_pin_control(); si5351c_disable_oeb_pin_control(&clock_gen);
si5351c_power_down_all_clocks(); si5351c_power_down_all_clocks(&clock_gen);
si5351c_set_crystal_configuration(); si5351c_set_crystal_configuration(&clock_gen);
si5351c_enable_xo_and_ms_fanout(); si5351c_enable_xo_and_ms_fanout(&clock_gen);
si5351c_configure_pll_sources(); si5351c_configure_pll_sources(&clock_gen);
si5351c_configure_pll_multisynth(); si5351c_configure_pll_multisynth(&clock_gen);
#ifdef JELLYBEAN #ifdef JELLYBEAN
/* /*
@ -288,13 +565,13 @@ void cpu_clock_init(void)
*/ */
/* MS0/CLK0 is the source for the MAX2837 clock input. */ /* MS0/CLK0 is the source for the MAX2837 clock input. */
si5351c_configure_multisynth(0, 2048, 0, 1, 0); /* 40MHz */ si5351c_configure_multisynth(&clock_gen, 0, 2048, 0, 1, 0); /* 40MHz */
/* MS4/CLK4 is the source for the LPC43xx microcontroller. */ /* MS4/CLK4 is the source for the LPC43xx microcontroller. */
si5351c_configure_multisynth(4, 8021, 0, 3, 0); /* 12MHz */ si5351c_configure_multisynth(&clock_gen, 4, 8021, 0, 3, 0); /* 12MHz */
/* MS5/CLK5 is the source for the RFFC5071 mixer. */ /* MS5/CLK5 is the source for the RFFC5071 mixer. */
si5351c_configure_multisynth(5, 1536, 0, 1, 0); /* 50MHz */ si5351c_configure_multisynth(&clock_gen, 5, 1536, 0, 1, 0); /* 50MHz */
#endif #endif
#if (defined JAWBREAKER || defined HACKRF_ONE) #if (defined JAWBREAKER || defined HACKRF_ONE)
@ -311,32 +588,32 @@ void cpu_clock_init(void)
*/ */
/* MS3/CLK3 is the source for the external clock output. */ /* MS3/CLK3 is the source for the external clock output. */
si5351c_configure_multisynth(3, 80*128-512, 0, 1, 0); /* 800/80 = 10MHz */ si5351c_configure_multisynth(&clock_gen, 3, 80*128-512, 0, 1, 0); /* 800/80 = 10MHz */
/* MS4/CLK4 is the source for the RFFC5071 mixer. */ /* MS4/CLK4 is the source for the RFFC5071 mixer. */
si5351c_configure_multisynth(4, 16*128-512, 0, 1, 0); /* 800/16 = 50MHz */ si5351c_configure_multisynth(&clock_gen, 4, 16*128-512, 0, 1, 0); /* 800/16 = 50MHz */
/* MS5/CLK5 is the source for the MAX2837 clock input. */ /* MS5/CLK5 is the source for the MAX2837 clock input. */
si5351c_configure_multisynth(5, 20*128-512, 0, 1, 0); /* 800/20 = 40MHz */ si5351c_configure_multisynth(&clock_gen, 5, 20*128-512, 0, 1, 0); /* 800/20 = 40MHz */
/* MS6/CLK6 is unused. */ /* MS6/CLK6 is unused. */
/* MS7/CLK7 is the source for the LPC43xx microcontroller. */ /* MS7/CLK7 is the source for the LPC43xx microcontroller. */
uint8_t ms7data[] = { 90, 255, 20, 0 }; uint8_t ms7data[] = { 90, 255, 20, 0 };
si5351c_write(ms7data, sizeof(ms7data)); si5351c_write(&clock_gen, ms7data, sizeof(ms7data));
#endif #endif
/* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */ /* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */
sample_rate_set(10000000); sample_rate_set(10000000);
si5351c_set_clock_source(PLL_SOURCE_XTAL); si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL);
// soft reset // soft reset
uint8_t resetdata[] = { 177, 0xac }; uint8_t resetdata[] = { 177, 0xac };
si5351c_write(resetdata, sizeof(resetdata)); si5351c_write(&clock_gen, resetdata, sizeof(resetdata));
si5351c_enable_clock_outputs(); si5351c_enable_clock_outputs(&clock_gen);
//FIXME disable I2C //FIXME disable I2C
/* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */ /* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */
i2c0_init(255); i2c_bus_start(clock_gen.bus, &i2c_config_si5351c_fast_clock);
/* /*
* 12MHz clock is entering LPC XTAL1/OSC input now. On * 12MHz clock is entering LPC XTAL1/OSC input now. On
@ -411,6 +688,12 @@ void cpu_clock_init(void)
/* Switch APB3 clock over to use PLL1 (204MHz) */ /* Switch APB3 clock over to use PLL1 (204MHz) */
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_AUTOBLOCK(1) CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_AUTOBLOCK(1)
| CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1); | 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);
} }
@ -504,70 +787,14 @@ void cpu_clock_pll1_max_speed(void)
} }
void ssp1_init(void)
{
/*
* 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);
GPIO_SET(PORT_AD_CS) = PIN_AD_CS;
GPIO_DIR(PORT_AD_CS) |= PIN_AD_CS;
scu_pinmux(SCU_XCVR_CS, SCU_GPIO_FAST);
GPIO_SET(PORT_XCVR_CS) = PIN_XCVR_CS;
GPIO_DIR(PORT_XCVR_CS) |= PIN_XCVR_CS;
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */
scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
}
void ssp1_set_mode_max2837(void) void ssp1_set_mode_max2837(void)
{ {
/* FIXME speed up once everything is working reliably */ spi_bus_start(max2837.bus, &ssp_config_max2837);
/*
// 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
const uint8_t serial_clock_rate = 21;
const uint8_t clock_prescale_rate = 2;
ssp_init(SSP1_NUM,
SSP_DATA_16BITS,
SSP_FRAME_SPI,
SSP_CPOL_0_CPHA_0,
serial_clock_rate,
clock_prescale_rate,
SSP_MODE_NORMAL,
SSP_MASTER,
SSP_SLAVE_OUT_ENABLE);
} }
void ssp1_set_mode_max5864(void) void ssp1_set_mode_max5864(void)
{ {
/* FIXME speed up once everything is working reliably */ spi_bus_start(max5864.bus, &ssp_config_max5864);
/*
// 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
const uint8_t serial_clock_rate = 21;
const uint8_t clock_prescale_rate = 2;
ssp_init(SSP1_NUM,
SSP_DATA_8BITS,
SSP_FRAME_SPI,
SSP_CPOL_0_CPHA_0,
serial_clock_rate,
clock_prescale_rate,
SSP_MODE_NORMAL,
SSP_MASTER,
SSP_SLAVE_OUT_ENABLE);
} }
void pin_setup(void) { void pin_setup(void) {
@ -577,10 +804,10 @@ void pin_setup(void) {
scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO; gpio_input(&gpio_cpld_tdo);
GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK; gpio_input(&gpio_cpld_tck);
GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS; gpio_input(&gpio_cpld_tms);
GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI; gpio_input(&gpio_cpld_tdi);
/* Configure SCU Pin Mux as GPIO */ /* Configure SCU Pin Mux as GPIO */
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_NOPULL); scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_NOPULL);
@ -596,49 +823,62 @@ void pin_setup(void) {
#endif #endif
/* Configure all GPIO as Input (safe state) */ /* Configure all GPIO as Input (safe state) */
GPIO0_DIR = 0; gpio_init();
GPIO1_DIR = 0;
GPIO2_DIR = 0;
GPIO3_DIR = 0;
GPIO4_DIR = 0;
GPIO5_DIR = 0;
GPIO6_DIR = 0;
GPIO7_DIR = 0;
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */ gpio_output(&gpio_led[0]);
GPIO2_DIR |= (PIN_LED1 | PIN_LED2 | PIN_LED3); gpio_output(&gpio_led[1]);
gpio_output(&gpio_led[2]);
/* GPIO3[6] on P6_10 as output. */ gpio_output(&gpio_1v8_enable);
GPIO3_DIR |= PIN_EN1V8;
rf_path_pin_setup(); #ifdef HACKRF_ONE
/* Configure RF power supply (VAA) switch control signal as output */
gpio_output(&gpio_vaa_disable);
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */ /* Safe state: start with VAA turned off: */
scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); disable_rf_power();
scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); #endif
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
scu_pinmux(SCU_SSP1_SSEL, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); /* enable input on SCL and SDA pins */
SCU_SFSI2C0 = SCU_I2C0_NOMINAL;
spi_bus_start(&spi_bus_ssp1, &ssp_config_max2837);
spi_bus_start(&spi_bus_rffc5071, &rffc5071_spi_config);
rf_path_pin_setup(&rf_path);
/* Configure external clock in */ /* Configure external clock in */
scu_pinmux(SCU_PINMUX_GP_CLKIN, SCU_CLK_IN | SCU_CONF_FUNCTION1); scu_pinmux(SCU_PINMUX_GP_CLKIN, SCU_CLK_IN | SCU_CONF_FUNCTION1);
sgpio_configure_pin_functions(); sgpio_configure_pin_functions(&sgpio_config);
} }
void enable_1v8_power(void) { void enable_1v8_power(void) {
gpio_set(PORT_EN1V8, PIN_EN1V8); gpio_set(&gpio_1v8_enable);
} }
void disable_1v8_power(void) { void disable_1v8_power(void) {
gpio_clear(PORT_EN1V8, PIN_EN1V8); gpio_clear(&gpio_1v8_enable);
} }
#ifdef HACKRF_ONE #ifdef HACKRF_ONE
void enable_rf_power(void) { void enable_rf_power(void) {
gpio_clear(PORT_NO_VAA_ENABLE, PIN_NO_VAA_ENABLE); gpio_clear(&gpio_vaa_disable);
} }
void disable_rf_power(void) { void disable_rf_power(void) {
gpio_set(PORT_NO_VAA_ENABLE, PIN_NO_VAA_ENABLE); gpio_set(&gpio_vaa_disable);
} }
#endif #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]);
}

View File

@ -32,6 +32,17 @@ extern "C"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "si5351c.h"
#include "spi_ssp.h"
#include "max2837.h"
#include "max5864.h"
#include "rffc5071.h"
#include "w25q80bv.h"
#include "sgpio.h"
#include "rf_path.h"
#include "cpld_jtag.h"
/* hardware identification number */ /* hardware identification number */
#define BOARD_ID_JELLYBEAN 0 #define BOARD_ID_JELLYBEAN 0
#define BOARD_ID_JAWBREAKER 1 #define BOARD_ID_JAWBREAKER 1
@ -206,142 +217,6 @@ extern "C"
#define SCU_PINMUX_GP_CLKIN (P4_7) #define SCU_PINMUX_GP_CLKIN (P4_7)
/*
* GPIO Pins
*/
/* GPIO Output */
#define PIN_LED1 (BIT1) /* GPIO2[1] on P4_1 */
#define PIN_LED2 (BIT2) /* GPIO2[2] on P4_2 */
#define PIN_LED3 (BIT8) /* GPIO2[8] on P6_12 */
#define PORT_LED1_3 (GPIO2) /* PORT for LED1, 2 & 3 */
#define PIN_EN1V8 (BIT6) /* GPIO3[6] on P6_10 */
#define PORT_EN1V8 (GPIO3)
#define PIN_XCVR_CS (BIT15) /* GPIO0[15] on P1_20 */
#define PORT_XCVR_CS (GPIO0) /* PORT for CS */
#define PIN_XCVR_ENABLE (BIT6) /* GPIO2[6] on P4_6 */
#define PIN_XCVR_RXENABLE (BIT5) /* GPIO2[5] on P4_5 */
#define PIN_XCVR_TXENABLE (BIT4) /* GPIO2[4] on P4_4 */
#define PORT_XCVR_ENABLE (GPIO2) /* PORT for ENABLE, TXENABLE, RXENABLE */
#ifdef JELLYBEAN
#define PIN_XCVR_RXHP (BIT0) /* GPIO2[0] on P4_0 */
#define PORT_XCVR_RXHP (GPIO2)
#define PIN_XCVR_B1 (BIT9) /* GPIO2[9] on P5_0 */
#define PIN_XCVR_B2 (BIT10) /* GPIO2[10] on P5_1 */
#define PIN_XCVR_B3 (BIT11) /* GPIO2[11] on P5_2 */
#define PIN_XCVR_B4 (BIT12) /* GPIO2[12] on P5_3 */
#define PIN_XCVR_B5 (BIT13) /* GPIO2[13] on P5_4 */
#define PIN_XCVR_B6 (BIT14) /* GPIO2[14] on P5_5 */
#define PIN_XCVR_B7 (BIT15) /* GPIO2[15] on P5_6 */
#define PORT_XCVR_B (GPIO2)
#endif
#define PIN_AD_CS (BIT7) /* GPIO2[7] on P5_7 */
#define PORT_AD_CS (GPIO2) /* PORT for AD_CS */
#ifdef JELLYBEAN
#define PIN_MIXER_ENX (BIT8) /* GPIO3[8] on P7_0 */
#define PORT_MIXER_ENX (GPIO3)
#define PIN_MIXER_SCLK (BIT9) /* GPIO3[9] on P7_1 */
#define PORT_MIXER_SCLK (GPIO3)
#define PIN_MIXER_SDATA (BIT10) /* GPIO3[10] on P7_2 */
#define PORT_MIXER_SDATA (GPIO3)
#define PIN_MIXER_RESETX (BIT11) /* GPIO3[11] on P7_3 */
#define PORT_MIXER_RESETX (GPIO3)
#endif
#if (defined JAWBREAKER || defined HACKRF_ONE)
#define PIN_MIXER_ENX (BIT13) /* GPIO2[13] on P5_4 */
#define PORT_MIXER_ENX (GPIO2)
#define PIN_MIXER_SCLK (BIT6) /* GPIO5[6] on P2_6 */
#define PORT_MIXER_SCLK (GPIO5)
#define PIN_MIXER_SDATA (BIT3) /* GPIO3[3] on P6_4 */
#define PORT_MIXER_SDATA (GPIO3)
#define PIN_MIXER_RESETX (BIT14) /* GPIO2[14] on P5_5 */
#define PORT_MIXER_RESETX (GPIO2)
#endif
#ifdef JAWBREAKER
#define PIN_RF_LDO_ENABLE (BIT9) /* GPIO2[9] on P5_0 */
#define PORT_RF_LDO_ENABLE (GPIO2) /* PORT for RF_LDO_ENABLE */
#endif
#ifdef HACKRF_ONE
#define PIN_NO_VAA_ENABLE (BIT9) /* GPIO2[9] on P5_0 */
#define PORT_NO_VAA_ENABLE (GPIO2) /* PORT for NO_VAA_ENABLE */
#endif
#define PIN_FLASH_HOLD (BIT14) /* GPIO1[14] on P3_4 */
#define PIN_FLASH_WP (BIT15) /* GPIO1[15] on P3_5 */
#define PORT_FLASH (GPIO1)
#define PIN_SSP0_SSEL (BIT11) /* GPIO5[11] on P3_8 */
#define PORT_SSP0_SSEL (GPIO5)
/* RF switch control */
#ifdef HACKRF_ONE
#define PIN_HP (GPIOPIN0) /* GPIO2[0] on P4_0 */
#define PORT_HP (GPIO2)
#define PIN_LP (GPIOPIN10) /* GPIO2[10] on P5_1 */
#define PORT_LP (GPIO2)
#define PIN_TX_MIX_BP (GPIOPIN11) /* GPIO2[11] on P5_2 */
#define PORT_TX_MIX_BP (GPIO2)
#define PIN_NO_MIX_BYPASS (GPIOPIN0) /* GPIO1[0] on P1_7 */
#define PORT_NO_MIX_BYPASS (GPIO1)
#define PIN_RX_MIX_BP (GPIOPIN12) /* GPIO2[12] on P5_3 */
#define PORT_RX_MIX_BP (GPIO2)
#define PIN_TX_AMP (GPIOPIN15) /* GPIO2[15] on P5_6 */
#define PORT_TX_AMP (GPIO2)
#define PIN_TX (GPIOPIN15) /* GPIO5[15] on P6_7 */
#define PORT_TX (GPIO5)
#define PIN_MIX_BYPASS (GPIOPIN16) /* GPIO5[16] on P6_8 */
#define PORT_MIX_BYPASS (GPIO5)
#define PIN_RX (GPIOPIN5) /* GPIO5[5] on P2_5 */
#define PORT_RX (GPIO5)
#define PIN_NO_TX_AMP_PWR (GPIOPIN5) /* GPIO3[5] on P6_9 */
#define PORT_NO_TX_AMP_PWR (GPIO3)
#define PIN_AMP_BYPASS (GPIOPIN14) /* GPIO0[14] on P2_10 */
#define PORT_AMP_BYPASS (GPIO0)
#define PIN_RX_AMP (GPIOPIN11) /* GPIO1[11] on P2_11 */
#define PORT_RX_AMP (GPIO1)
#define PIN_NO_RX_AMP_PWR (GPIOPIN12) /* GPIO1[12] on P2_12 */
#define PORT_NO_RX_AMP_PWR (GPIO1)
#endif
/* GPIO Input */
#define PIN_BOOT0 (BIT8) /* GPIO0[8] on P1_1 */
#define PIN_BOOT1 (BIT9) /* GPIO0[9] on P1_2 */
#define PIN_BOOT2 (BIT7) /* GPIO5[7] on P2_8 */
#define PIN_BOOT3 (BIT10) /* GPIO1[10] on P2_9 */
/* CPLD JTAG interface GPIO pins */
#define PIN_CPLD_TDO (GPIOPIN18)
#define PORT_CPLD_TDO (GPIO5)
#define PIN_CPLD_TCK (GPIOPIN0)
#define PORT_CPLD_TCK (GPIO3)
#ifdef HACKRF_ONE
#define PIN_CPLD_TMS (GPIOPIN4)
#define PORT_CPLD_TMS (GPIO3)
#define PIN_CPLD_TDI (GPIOPIN1)
#define PORT_CPLD_TDI (GPIO3)
#else
#define PIN_CPLD_TMS (GPIOPIN1)
#define PORT_CPLD_TMS (GPIO3)
#define PIN_CPLD_TDI (GPIOPIN4)
#define PORT_CPLD_TDI (GPIO3)
#endif
/* Read GPIO Pin */
#define GPIO_STATE(port, pin) ((GPIO_PIN(port) & (pin)) == (pin))
#define BOOT0_STATE GPIO_STATE(GPIO0, PIN_BOOT0)
#define BOOT1_STATE GPIO_STATE(GPIO0, PIN_BOOT1)
#define BOOT2_STATE GPIO_STATE(GPIO5, PIN_BOOT2)
#define BOOT3_STATE GPIO_STATE(GPIO1, PIN_BOOT3)
#define MIXER_SDATA_STATE GPIO_STATE(PORT_MIXER_SDATA, PIN_MIXER_SDATA)
#define CPLD_TDO_STATE GPIO_STATE(PORT_CPLD_TDO, PIN_CPLD_TDO)
/* TODO add other Pins */
typedef enum { typedef enum {
TRANSCEIVER_MODE_OFF = 0, TRANSCEIVER_MODE_OFF = 0,
TRANSCEIVER_MODE_RX = 1, TRANSCEIVER_MODE_RX = 1,
@ -352,10 +227,23 @@ typedef enum {
void delay(uint32_t duration); 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 rffc5071_driver_t rffc5072;
extern w25q80bv_driver_t spi_flash;
extern sgpio_config_t sgpio_config;
extern rf_path_t rf_path;
extern jtag_t jtag_cpld;
void cpu_clock_init(void); void cpu_clock_init(void);
void cpu_clock_pll1_low_speed(void); void cpu_clock_pll1_low_speed(void);
void cpu_clock_pll1_max_speed(void); void cpu_clock_pll1_max_speed(void);
void ssp1_init(void);
void ssp1_set_mode_max2837(void); void ssp1_set_mode_max2837(void);
void ssp1_set_mode_max5864(void); void ssp1_set_mode_max5864(void);
@ -373,6 +261,16 @@ void enable_rf_power(void);
void disable_rf_power(void); void disable_rf_power(void);
#endif #endif
typedef enum {
LED1 = 0,
LED2 = 1,
LED3 = 2,
} led_t;
void led_on(const led_t led);
void led_off(const led_t led);
void led_toggle(const led_t led);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

39
firmware/common/i2c_bus.c Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "i2c_bus.h"
void i2c_bus_start(i2c_bus_t* const bus, const void* const config) {
bus->start(bus, config);
}
void i2c_bus_stop(i2c_bus_t* const bus) {
bus->stop(bus);
}
void i2c_bus_transfer(
i2c_bus_t* const bus,
const uint_fast8_t slave_address,
const uint8_t* const tx, const size_t tx_count,
uint8_t* const rx, const size_t rx_count
) {
bus->transfer(bus, slave_address, tx, tx_count, rx, rx_count);
}

52
firmware/common/i2c_bus.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __I2C_BUS_H__
#define __I2C_BUS_H__
#include <stdint.h>
#include <stddef.h>
struct i2c_bus_t;
typedef struct i2c_bus_t i2c_bus_t;
struct i2c_bus_t {
void* const obj;
void (*start)(i2c_bus_t* const bus, const void* const config);
void (*stop)(i2c_bus_t* const bus);
void (*transfer)(
i2c_bus_t* const bus,
const uint_fast8_t slave_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 slave_address,
const uint8_t* const tx, const size_t tx_count,
uint8_t* const rx, const size_t rx_count
);
#endif/*__I2C_BUS_H__*/

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

@ -0,0 +1,62 @@
/*
* 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 slave_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;
i2c_tx_start(port);
i2c_tx_byte(port, (slave_address << 1) | I2C_WRITE);
for(size_t i=0; i<count_tx; i++) {
i2c_tx_byte(port, data_tx[i]);
}
if( data_rx ) {
i2c_tx_start(port);
i2c_tx_byte(port, (slave_address << 1) | I2C_READ);
for(size_t i=0; i<count_rx; i++) {
data_rx[i] = i2c_rx_byte(port);
}
}
i2c_stop(port);
}

42
firmware/common/i2c_lpc.h Normal file
View File

@ -0,0 +1,42 @@
/*
* 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 "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 slave_address,
const uint8_t* const data_tx, const size_t count_tx,
uint8_t* const data_rx, const size_t count_rx
);
#endif/*__I2C_LPC_H__*/

View File

@ -1,3 +1,25 @@
/*
* 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 * 'gcc -DTEST -DDEBUG -O2 -o test max2837.c' prints out what test
* program would do if it had a real spi library * program would do if it had a real spi library
@ -11,19 +33,8 @@
#include "max2837.h" #include "max2837.h"
#include "max2837_regs.def" // private register def macros #include "max2837_regs.def" // private register def macros
#if (defined DEBUG || defined BUS_PIRATE)
#include <stdio.h>
#define LOG printf
#else
#define LOG(x,...)
#include <libopencm3/lpc43xx/ssp.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/gpio.h>
#include "hackrf_core.h"
#endif
/* Default register values. */ /* Default register values. */
static uint16_t max2837_regs_default[MAX2837_NUM_REGS] = { static const uint16_t max2837_regs_default[MAX2837_NUM_REGS] = {
0x150, /* 0 */ 0x150, /* 0 */
0x002, /* 1 */ 0x002, /* 1 */
0x1f4, /* 2 */ 0x1f4, /* 2 */
@ -62,283 +73,130 @@ static uint16_t max2837_regs_default[MAX2837_NUM_REGS] = {
0x080, /* 30 */ 0x080, /* 30 */
0x000 }; /* 31 */ 0x000 }; /* 31 */
uint16_t max2837_regs[MAX2837_NUM_REGS];
/* Mark all regsisters dirty so all will be written at init. */
uint32_t max2837_regs_dirty = 0xffffffff;
/* Set up all registers according to defaults specified in docs. */ /* Set up all registers according to defaults specified in docs. */
void max2837_init(void) static void max2837_init(max2837_driver_t* const drv)
{ {
LOG("# max2837_init\n"); drv->target_init(drv);
memcpy(max2837_regs, max2837_regs_default, sizeof(max2837_regs)); max2837_set_mode(drv, MAX2837_MODE_SHUTDOWN);
max2837_regs_dirty = 0xffffffff;
memcpy(drv->regs, max2837_regs_default, sizeof(drv->regs));
drv->regs_dirty = 0xffffffff;
/* Write default register values to chip. */ /* Write default register values to chip. */
max2837_regs_commit(); max2837_regs_commit(drv);
} }
/* /*
* Set up pins for GPIO and SPI control, configure SSP peripheral for SPI, and * Set up pins for GPIO and SPI control, configure SSP peripheral for SPI, and
* set our own default register configuration. * set our own default register configuration.
*/ */
void max2837_setup(void) void max2837_setup(max2837_driver_t* const drv)
{ {
LOG("# max2837_setup\n"); max2837_init(drv);
#if !defined TEST
/* Configure XCVR_CTL GPIO pins. */
#ifdef JELLYBEAN
scu_pinmux(SCU_XCVR_RXHP, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B1, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B2, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B3, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B4, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B5, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B6, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B7, SCU_GPIO_FAST);
#endif
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. */
GPIO2_DIR |= (PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE);
#ifdef JELLYBEAN
GPIO_DIR(PORT_XCVR_RXHP) |= PIN_XCVR_RXHP;
GPIO_DIR(PORT_XCVR_B) |=
PIN_XCVR_B1
| PIN_XCVR_B2
| PIN_XCVR_B3
| PIN_XCVR_B4
| PIN_XCVR_B5
| PIN_XCVR_B6
| PIN_XCVR_B7
;
#endif
max2837_mode_shutdown();
#ifdef JELLYBEAN
gpio_set(PORT_XCVR_RXHP, PIN_XCVR_RXHP);
gpio_set(PORT_XCVR_B,
PIN_XCVR_B1
| PIN_XCVR_B2
| PIN_XCVR_B3
| PIN_XCVR_B4
| PIN_XCVR_B5
| PIN_XCVR_B6
| PIN_XCVR_B7
);
#endif
#endif
max2837_init();
LOG("# max2837_init done\n");
/* Use SPI control instead of B1-B7 pins for gain settings. */ /* Use SPI control instead of B1-B7 pins for gain settings. */
set_MAX2837_TXVGA_GAIN_SPI_EN(1); set_MAX2837_TXVGA_GAIN_SPI_EN(drv, 1);
set_MAX2837_TXVGA_GAIN_MSB_SPI_EN(1); set_MAX2837_TXVGA_GAIN_MSB_SPI_EN(drv, 1);
//set_MAX2837_TXVGA_GAIN(0x3f); /* maximum attenuation */ //set_MAX2837_TXVGA_GAIN(0x3f); /* maximum attenuation */
set_MAX2837_TXVGA_GAIN(0x00); /* minimum attenuation */ set_MAX2837_TXVGA_GAIN(drv, 0x00); /* minimum attenuation */
set_MAX2837_VGAMUX_enable(1); set_MAX2837_VGAMUX_enable(drv, 1);
set_MAX2837_VGA_EN(1); set_MAX2837_VGA_EN(drv, 1);
set_MAX2837_HPC_RXGAIN_EN(0); set_MAX2837_HPC_RXGAIN_EN(drv, 0);
set_MAX2837_HPC_STOP(MAX2837_STOP_1K); set_MAX2837_HPC_STOP(drv, MAX2837_STOP_1K);
set_MAX2837_LNAgain_SPI_EN(1); set_MAX2837_LNAgain_SPI_EN(drv, 1);
set_MAX2837_LNAgain(MAX2837_LNAgain_MAX); /* maximum gain */ set_MAX2837_LNAgain(drv, MAX2837_LNAgain_MAX); /* maximum gain */
set_MAX2837_VGAgain_SPI_EN(1); set_MAX2837_VGAgain_SPI_EN(drv, 1);
set_MAX2837_VGA(0x18); /* reasonable gain for noisy 2.4GHz environment */ set_MAX2837_VGA(drv, 0x18); /* reasonable gain for noisy 2.4GHz environment */
/* maximum rx output common-mode voltage */ /* maximum rx output common-mode voltage */
set_MAX2837_BUFF_VCM(MAX2837_BUFF_VCM_1_25); set_MAX2837_BUFF_VCM(drv, MAX2837_BUFF_VCM_1_25);
/* configure baseband filter for 8 MHz TX */ /* configure baseband filter for 8 MHz TX */
set_MAX2837_LPF_EN(1); set_MAX2837_LPF_EN(drv, 1);
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_RxLPF); set_MAX2837_ModeCtrl(drv, MAX2837_ModeCtrl_RxLPF);
set_MAX2837_FT(MAX2837_FT_5M); set_MAX2837_FT(drv, MAX2837_FT_5M);
max2837_regs_commit(); max2837_regs_commit(drv);
} }
/* SPI register read. */ static uint16_t max2837_read(max2837_driver_t* const drv, uint8_t r) {
uint16_t max2837_spi_read(uint8_t r) { uint16_t value = (1 << 15) | (r << 10);
gpio_clear(PORT_XCVR_CS, PIN_XCVR_CS); spi_bus_transfer(drv->bus, &value, 1);
const uint16_t value = ssp_transfer(SSP1_NUM, (uint16_t)((1 << 15) | (r << 10)));
gpio_set(PORT_XCVR_CS, PIN_XCVR_CS);
return value & 0x3ff; return value & 0x3ff;
} }
/* SPI register write */ static void max2837_write(max2837_driver_t* const drv, uint8_t r, uint16_t v) {
void max2837_spi_write(uint8_t r, uint16_t v) { uint16_t value = (r << 10) | (v & 0x3ff);
spi_bus_transfer(drv->bus, &value, 1);
#ifdef BUS_PIRATE
LOG("{0x%02x 0x%02x]\n", 0x00 | ((uint16_t)r<<2) | ((v>>8) & 0x3),
v & 0xff);
#elif DEBUG
LOG("0x%03x -> reg%d\n", v, r);
#else
gpio_clear(PORT_XCVR_CS, PIN_XCVR_CS);
ssp_transfer(SSP1_NUM, (uint16_t)((r << 10) | (v & 0x3ff)));
gpio_set(PORT_XCVR_CS, PIN_XCVR_CS);
#endif
} }
uint16_t max2837_reg_read(uint8_t r) uint16_t max2837_reg_read(max2837_driver_t* const drv, uint8_t r)
{ {
if ((max2837_regs_dirty >> r) & 0x1) { if ((drv->regs_dirty >> r) & 0x1) {
max2837_regs[r] = max2837_spi_read(r); drv->regs[r] = max2837_read(drv, r);
}; };
return max2837_regs[r]; return drv->regs[r];
} }
void max2837_reg_write(uint8_t r, uint16_t v) void max2837_reg_write(max2837_driver_t* const drv, uint8_t r, uint16_t v)
{ {
max2837_regs[r] = v; drv->regs[r] = v;
max2837_spi_write(r, v); max2837_write(drv, r, v);
MAX2837_REG_SET_CLEAN(r); MAX2837_REG_SET_CLEAN(drv, r);
} }
/* This functions should not be needed, and might be confusing. DELETE. */ static inline void max2837_reg_commit(max2837_driver_t* const drv, uint8_t r)
void max2837_regs_read(void)
{ {
; max2837_reg_write(drv, r, drv->regs[r]);
} }
static inline void max2837_reg_commit(uint8_t r) void max2837_regs_commit(max2837_driver_t* const drv)
{
max2837_reg_write(r,max2837_regs[r]);
}
void max2837_regs_commit(void)
{ {
int r; int r;
for(r = 0; r < MAX2837_NUM_REGS; r++) { for(r = 0; r < MAX2837_NUM_REGS; r++) {
if ((max2837_regs_dirty >> r) & 0x1) { if ((drv->regs_dirty >> r) & 0x1) {
max2837_reg_commit(r); max2837_reg_commit(drv, r);
} }
} }
} }
void max2837_mode_shutdown(void) { void max2837_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode) {
/* All circuit blocks are powered down, except the 4-wire serial bus drv->set_mode(drv, new_mode);
* and its internal programmable registers.
*/
gpio_clear(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
} }
void max2837_mode_standby(void) { max2837_mode_t max2837_mode(max2837_driver_t* const drv) {
/* Used to enable the frequency synthesizer block while the rest of the return drv->mode;
* device is powered down. In this mode, PLL, VCO, and LO generator
* are on, so that Tx or Rx modes can be quickly enabled from this mode.
* These and other blocks can be selectively enabled in this mode.
*/
gpio_clear(PORT_XCVR_ENABLE, (PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
gpio_set(PORT_XCVR_ENABLE, PIN_XCVR_ENABLE);
} }
void max2837_mode_tx(void) { void max2837_start(max2837_driver_t* const drv)
/* All Tx circuit blocks are powered on. The external PA is powered on
* after a programmable delay using the on-chip PA bias DAC. The slow-
* charging Rx circuits are in a precharged idle-off state for fast
* Tx-to-Rx turnaround time.
*/
gpio_clear(PORT_XCVR_ENABLE, PIN_XCVR_RXENABLE);
gpio_set(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_TXENABLE));
}
void max2837_mode_rx(void) {
/* All Rx circuit blocks are powered on and active. Antenna signal is
* applied; RF is downconverted, filtered, and buffered at Rx BB I and Q
* outputs. The slow- charging Tx circuits are in a precharged idle-off
* state for fast Rx-to-Tx turnaround time.
*/
gpio_clear(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE);
gpio_set(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE));
}
max2837_mode_t max2837_mode(void) {
if( gpio_get(PORT_XCVR_ENABLE, PIN_XCVR_ENABLE) ) {
if( gpio_get(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE) ) {
return MAX2837_MODE_TX;
} else if( gpio_get(PORT_XCVR_ENABLE, PIN_XCVR_RXENABLE) ) {
return MAX2837_MODE_RX;
} else {
return MAX2837_MODE_STANDBY;
}
} else {
return MAX2837_MODE_SHUTDOWN;
}
}
void max2837_set_mode(const max2837_mode_t new_mode) {
switch(new_mode) {
case MAX2837_MODE_SHUTDOWN:
max2837_mode_shutdown();
break;
case MAX2837_MODE_STANDBY:
max2837_mode_standby();
break;
case MAX2837_MODE_TX:
max2837_mode_tx();
break;
case MAX2837_MODE_RX:
max2837_mode_rx();
break;
default:
break;
}
}
void max2837_start(void)
{ {
LOG("# max2837_start\n"); set_MAX2837_EN_SPI(drv, 1);
set_MAX2837_EN_SPI(1); max2837_regs_commit(drv);
max2837_regs_commit(); max2837_set_mode(drv, MAX2837_MODE_STANDBY);
#if !defined TEST
max2837_mode_standby();
#endif
} }
void max2837_tx(void) void max2837_tx(max2837_driver_t* const drv)
{ {
LOG("# max2837_tx\n"); set_MAX2837_ModeCtrl(drv, MAX2837_ModeCtrl_TxLPF);
#if !defined TEST max2837_regs_commit(drv);
max2837_set_mode(drv, MAX2837_MODE_TX);
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_TxLPF);
max2837_regs_commit();
max2837_mode_tx();
#endif
} }
void max2837_rx(void) void max2837_rx(max2837_driver_t* const drv)
{ {
LOG("# max2837_rx\n"); set_MAX2837_ModeCtrl(drv, MAX2837_ModeCtrl_RxLPF);
max2837_regs_commit(drv);
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_RxLPF); max2837_set_mode(drv, MAX2837_MODE_RX);
max2837_regs_commit();
#if !defined TEST
max2837_mode_rx();
#endif
} }
void max2837_stop(void) void max2837_stop(max2837_driver_t* const drv)
{ {
LOG("# max2837_stop\n"); set_MAX2837_EN_SPI(drv, 0);
set_MAX2837_EN_SPI(0); max2837_regs_commit(drv);
max2837_regs_commit(); max2837_set_mode(drv, MAX2837_MODE_SHUTDOWN);
#if !defined TEST
max2837_mode_shutdown();
#endif
} }
void max2837_set_frequency(uint32_t freq) void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq)
{ {
uint8_t band; uint8_t band;
uint8_t lna_band; uint8_t lna_band;
@ -366,9 +224,6 @@ void max2837_set_frequency(uint32_t freq)
lna_band = MAX2837_LNAband_2_6; lna_band = MAX2837_LNAband_2_6;
} }
LOG("# max2837_set_frequency %ld, band %d, lna band %d\n",
freq, band, lna_band);
/* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */ /* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */
div_int = freq / 30000000; div_int = freq / 30000000;
div_rem = freq % 30000000; div_rem = freq % 30000000;
@ -382,22 +237,21 @@ void max2837_set_frequency(uint32_t freq)
div_rem -= div_cmp; div_rem -= div_cmp;
} }
} }
LOG("# int %ld, frac %ld\n", div_int, div_frac);
/* Band settings */ /* Band settings */
set_MAX2837_LOGEN_BSW(band); set_MAX2837_LOGEN_BSW(drv, band);
set_MAX2837_LNAband(lna_band); set_MAX2837_LNAband(drv, lna_band);
/* Write order matters here, so commit INT and FRAC_HI before /* Write order matters here, so commit INT and FRAC_HI before
* committing FRAC_LO, which is the trigger for VCO * committing FRAC_LO, which is the trigger for VCO
* auto-select. TODO - it's cleaner this way, but it would be * auto-select. TODO - it's cleaner this way, but it would be
* faster to explicitly commit the registers explicitly so the * faster to explicitly commit the registers explicitly so the
* dirty bits aren't scanned twice. */ * dirty bits aren't scanned twice. */
set_MAX2837_SYN_INT(div_int); set_MAX2837_SYN_INT(drv, div_int);
set_MAX2837_SYN_FRAC_HI((div_frac >> 10) & 0x3ff); set_MAX2837_SYN_FRAC_HI(drv, (div_frac >> 10) & 0x3ff);
max2837_regs_commit(); max2837_regs_commit(drv);
set_MAX2837_SYN_FRAC_LO(div_frac & 0x3ff); set_MAX2837_SYN_FRAC_LO(drv, div_frac & 0x3ff);
max2837_regs_commit(); max2837_regs_commit(drv);
} }
typedef struct { typedef struct {
@ -425,7 +279,7 @@ static const max2837_ft_t max2837_ft[] = {
{ 0, 0 }, { 0, 0 },
}; };
bool max2837_set_lpf_bandwidth(const uint32_t bandwidth_hz) { bool max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandwidth_hz) {
const max2837_ft_t* p = max2837_ft; const max2837_ft_t* p = max2837_ft;
while( p->bandwidth_hz != 0 ) { while( p->bandwidth_hz != 0 ) {
if( p->bandwidth_hz >= bandwidth_hz ) { if( p->bandwidth_hz >= bandwidth_hz ) {
@ -435,15 +289,15 @@ bool max2837_set_lpf_bandwidth(const uint32_t bandwidth_hz) {
} }
if( p->bandwidth_hz != 0 ) { if( p->bandwidth_hz != 0 ) {
set_MAX2837_FT(p->ft); set_MAX2837_FT(drv, p->ft);
max2837_regs_commit(); max2837_regs_commit(drv);
return true; return true;
} else { } else {
return false; return false;
} }
} }
bool max2837_set_lna_gain(const uint32_t gain_db) { bool max2837_set_lna_gain(max2837_driver_t* const drv, const uint32_t gain_db) {
uint16_t val; uint16_t val;
switch(gain_db){ switch(gain_db){
case 40: case 40:
@ -467,21 +321,21 @@ bool max2837_set_lna_gain(const uint32_t gain_db) {
default: default:
return false; return false;
} }
set_MAX2837_LNAgain(val); set_MAX2837_LNAgain(drv, val);
max2837_reg_commit(1); max2837_reg_commit(drv, 1);
return true; return true;
} }
bool max2837_set_vga_gain(const uint32_t gain_db) { bool max2837_set_vga_gain(max2837_driver_t* const drv, const uint32_t gain_db) {
if( (gain_db & 0x1) || gain_db > 62)/* 0b11111*2 */ if( (gain_db & 0x1) || gain_db > 62)/* 0b11111*2 */
return false; return false;
set_MAX2837_VGA( 31-(gain_db >> 1) ); set_MAX2837_VGA(drv, 31-(gain_db >> 1) );
max2837_reg_commit(5); max2837_reg_commit(drv, 5);
return true; return true;
} }
bool max2837_set_txvga_gain(const uint32_t gain_db) { bool max2837_set_txvga_gain(max2837_driver_t* const drv, const uint32_t gain_db) {
uint16_t val=0; uint16_t val=0;
if(gain_db <16){ if(gain_db <16){
val = 31-gain_db; val = 31-gain_db;
@ -490,18 +344,7 @@ bool max2837_set_txvga_gain(const uint32_t gain_db) {
val = 31-(gain_db-16); val = 31-(gain_db-16);
} }
set_MAX2837_TXVGA_GAIN(val); set_MAX2837_TXVGA_GAIN(drv, val);
max2837_reg_commit(29); max2837_reg_commit(drv, 29);
return true; return true;
} }
#ifdef TEST
int main(int ac, char **av)
{
max2837_setup();
max2837_set_frequency(2441000000);
max2837_start();
max2837_tx();
max2837_stop();
}
#endif //TEST

View File

@ -1,42 +1,38 @@
/*
* 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 #ifndef __MAX2837_H
#define __MAX2837_H #define __MAX2837_H
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/* TODO - make this a private header for max2837.c only, make new max2837.h */ #include "gpio.h"
#include "spi_bus.h"
/* 32 registers, each containing 10 bits of data. */ /* 32 registers, each containing 10 bits of data. */
#define MAX2837_NUM_REGS 32 #define MAX2837_NUM_REGS 32
#define MAX2837_DATA_REGS_MAX_VALUE 1024 #define MAX2837_DATA_REGS_MAX_VALUE 1024
/* TODO - these externs will be local to max2837.c ... don't define here? */
extern uint16_t max2837_regs[MAX2837_NUM_REGS];
extern uint32_t max2837_regs_dirty;
#define MAX2837_REG_SET_CLEAN(r) max2837_regs_dirty &= ~(1UL<<r)
#define MAX2837_REG_SET_DIRTY(r) max2837_regs_dirty |= (1UL<<r)
/* Initialize chip. */
extern void max2837_init(void);
extern void max2837_setup(void);
/* Read a register via SPI. Save a copy to memory and return
* value. Mark clean. */
extern uint16_t max2837_reg_read(uint8_t r);
/* Write value to register via SPI and save a copy to memory. Mark
* clean. */
extern void max2837_reg_write(uint8_t r, uint16_t v);
/* Read all registers from chip and copy to memory. Mark all clean. */
extern void max2837_regs_read(void);
/* 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(void);
typedef enum { typedef enum {
MAX2837_MODE_SHUTDOWN, MAX2837_MODE_SHUTDOWN,
MAX2837_MODE_STANDBY, MAX2837_MODE_STANDBY,
@ -44,27 +40,63 @@ typedef enum {
MAX2837_MODE_RX MAX2837_MODE_RX
} max2837_mode_t; } max2837_mode_t;
void max2837_mode_shutdown(void); struct max2837_driver_t;
void max2837_mode_standby(void); typedef struct max2837_driver_t max2837_driver_t;
void max2837_mode_tx(void);
void max2837_mode_rx(void);
max2837_mode_t max2837_mode(void); struct max2837_driver_t {
void max2837_set_mode(const max2837_mode_t new_mode); spi_bus_t* const bus;
gpio_t gpio_enable;
gpio_t gpio_rx_enable;
gpio_t gpio_tx_enable;
#ifdef JELLYBEAN
gpio_t gpio_rxhp;
gpio_t gpio_b1;
gpio_t gpio_b2;
gpio_t gpio_b3;
gpio_t gpio_b4;
gpio_t gpio_b5;
gpio_t gpio_b6;
gpio_t gpio_b7;
#endif
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 */ /* Turn on/off all chip functions. Does not control oscillator and CLKOUT */
extern void max2837_start(void); extern void max2837_start(max2837_driver_t* const drv);
extern void max2837_stop(void); extern void max2837_stop(max2837_driver_t* const drv);
/* Set frequency in Hz. Frequency setting is a multi-step function /* Set frequency in Hz. Frequency setting is a multi-step function
* where order of register writes matters. */ * where order of register writes matters. */
extern void max2837_set_frequency(uint32_t freq); extern void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq);
bool max2837_set_lpf_bandwidth(const uint32_t bandwidth_hz); bool max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandwidth_hz);
bool max2837_set_lna_gain(const uint32_t gain_db); bool max2837_set_lna_gain(max2837_driver_t* const drv, const uint32_t gain_db);
bool max2837_set_vga_gain(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(const uint32_t gain_db); bool max2837_set_txvga_gain(max2837_driver_t* const drv, const uint32_t gain_db);
extern void max2837_tx(void); extern void max2837_tx(max2837_driver_t* const drv);
extern void max2837_rx(void); extern void max2837_rx(max2837_driver_t* const drv);
#endif // __MAX2837_H #endif // __MAX2837_H

View File

@ -9,19 +9,22 @@
* (structs). This may be used in firmware, or on host predefined * (structs). This may be used in firmware, or on host predefined
* register loads. */ * 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 /* On set_, register is always set dirty, even if nothing
* changed. This makes sure that write that have side effects, * changed. This makes sure that write that have side effects,
* e.g. frequency setting, are not skipped. */ * e.g. frequency setting, are not skipped. */
/* n=name, r=regnum, o=offset (bits from LSB), l=length (bits) */ /* n=name, r=regnum, o=offset (bits from LSB), l=length (bits) */
#define __MREG__(n,r,o,l) \ #define __MREG__(n,r,o,l) \
static inline uint16_t get_##n(void) { \ static inline uint16_t get_##n(max2837_driver_t* const _d) { \
return (max2837_regs[r] >> (o-l+1)) & ((1<<l)-1); \ return (_d->regs[r] >> (o-l+1)) & ((1<<l)-1); \
} \ } \
static inline void set_##n(uint16_t v) { \ static inline void set_##n(max2837_driver_t* const _d, uint16_t v) { \
max2837_regs[r] &= ~(((1<<l)-1)<<(o-l+1)); \ _d->regs[r] &= ~(((1<<l)-1)<<(o-l+1)); \
max2837_regs[r] |= ((v&((1<<l)-1))<<(o-l+1)); \ _d->regs[r] |= ((v&((1<<l)-1))<<(o-l+1)); \
MAX2837_REG_SET_DIRTY(r); \ MAX2837_REG_SET_DIRTY(_d, r); \
} }
/* REG 0 */ /* REG 0 */

View File

@ -0,0 +1,105 @@
/*
* 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_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
scu_pinmux(SCU_XCVR_CS, SCU_GPIO_FAST);
/* Configure XCVR_CTL GPIO pins. */
#ifdef JELLYBEAN
scu_pinmux(SCU_XCVR_RXHP, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B1, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B2, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B3, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B4, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B5, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B6, SCU_GPIO_FAST);
scu_pinmux(SCU_XCVR_B7, SCU_GPIO_FAST);
#endif
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);
#ifdef JELLYBEAN
gpio_output(drv->gpio_rxhp);
gpio_output(drv->gpio_b1);
gpio_output(drv->gpio_b2);
gpio_output(drv->gpio_b3);
gpio_output(drv->gpio_b4);
gpio_output(drv->gpio_b5);
gpio_output(drv->gpio_b6);
gpio_output(drv->gpio_b7);
#endif
#ifdef JELLYBEAN
gpio_set(drv->gpio_rxhp);
gpio_set(drv->gpio_b1);
gpio_set(drv->gpio_b2);
gpio_set(drv->gpio_b3);
gpio_set(drv->gpio_b4);
gpio_set(drv->gpio_b5);
gpio_set(drv->gpio_b6);
gpio_set(drv->gpio_b7);
#endif
}
void max2837_target_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode) {
/* MAX2837_MODE_SHUTDOWN:
* All circuit blocks are powered down, except the 4-wire serial bus
* and its internal programmable registers.
*
* MAX2837_MODE_STANDBY:
* Used to enable the frequency synthesizer block while the rest of the
* device is powered down. In this mode, PLL, VCO, and LO generator
* are on, so that Tx or Rx modes can be quickly enabled from this mode.
* These and other blocks can be selectively enabled in this mode.
*
* MAX2837_MODE_TX:
* All Tx circuit blocks are powered on. The external PA is powered on
* after a programmable delay using the on-chip PA bias DAC. The slow-
* charging Rx circuits are in a precharged idle-off state for fast
* Tx-to-Rx turnaround time.
*
* MAX2837_MODE_RX:
* All Rx circuit blocks are powered on and active. Antenna signal is
* applied; RF is downconverted, filtered, and buffered at Rx BB I and Q
* outputs. The slow- charging Tx circuits are in a precharged idle-off
* state for fast Rx-to-Tx turnaround time.
*/
gpio_write(drv->gpio_enable, new_mode != MAX2837_MODE_SHUTDOWN);
gpio_write(drv->gpio_rx_enable, new_mode == MAX2837_MODE_RX);
gpio_write(drv->gpio_tx_enable, new_mode == MAX2837_MODE_TX);
drv->mode = new_mode;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2012 Will Code? (TODO: Proper attribution)
* Copyright 2014 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __MAX2837_TARGET_H
#define __MAX2837_TARGET_H
#include "max2837.h"
void max2837_target_init(max2837_driver_t* const drv);
void max2837_target_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode);
#endif // __MAX2837_TARGET_H

View File

@ -21,16 +21,18 @@
#include <stdint.h> #include <stdint.h>
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/ssp.h>
#include "hackrf_core.h"
#include "max5864.h" #include "max5864.h"
void max5864_spi_write(uint_fast8_t value) { static void max5864_write(max5864_driver_t* const drv, uint8_t value) {
gpio_clear(PORT_AD_CS, PIN_AD_CS); spi_bus_transfer(drv->bus, &value, 1);
ssp_transfer(SSP1_NUM, value); }
gpio_set(PORT_AD_CS, PIN_AD_CS);
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": /* Set MAX5864 operation mode to "Shutdown":
@ -39,9 +41,9 @@ void max5864_spi_write(uint_fast8_t value) {
* ADCs: off (bus is tri-stated) * ADCs: off (bus is tri-stated)
* DACs: off (set input bus to zero or OVdd) * DACs: off (set input bus to zero or OVdd)
*/ */
void max5864_shutdown() void max5864_shutdown(max5864_driver_t* const drv)
{ {
max5864_spi_write(0x00); max5864_write(drv, 0x00);
} }
/* Set MAX5864 operation mode to "Standby": /* Set MAX5864 operation mode to "Standby":
@ -50,9 +52,9 @@ void max5864_shutdown()
* ADCs: off (bus is tri-stated) * ADCs: off (bus is tri-stated)
* DACs: off (set input bus to zero or OVdd) * DACs: off (set input bus to zero or OVdd)
*/ */
void max5864_standby() void max5864_standby(max5864_driver_t* const drv)
{ {
max5864_spi_write(0x05); max5864_write(drv, 0x05);
} }
/* Set MAX5864 operation mode to "Idle": /* Set MAX5864 operation mode to "Idle":
@ -61,9 +63,9 @@ void max5864_standby()
* ADCs: off (bus is tri-stated) * ADCs: off (bus is tri-stated)
* DACs: off (set input bus to zero or OVdd) * DACs: off (set input bus to zero or OVdd)
*/ */
void max5864_idle() void max5864_idle(max5864_driver_t* const drv)
{ {
max5864_spi_write(0x01); max5864_write(drv, 0x01);
} }
/* Set MAX5864 operation mode to "Rx": /* Set MAX5864 operation mode to "Rx":
@ -72,9 +74,9 @@ void max5864_idle()
* ADCs: on * ADCs: on
* DACs: off (set input bus to zero or OVdd) * DACs: off (set input bus to zero or OVdd)
*/ */
void max5864_rx() void max5864_rx(max5864_driver_t* const drv)
{ {
max5864_spi_write(0x02); max5864_write(drv, 0x02);
} }
/* Set MAX5864 operation mode to "Tx": /* Set MAX5864 operation mode to "Tx":
@ -83,9 +85,9 @@ void max5864_rx()
* ADCs: off (bus is tri-stated) * ADCs: off (bus is tri-stated)
* DACs: on * DACs: on
*/ */
void max5864_tx() void max5864_tx(max5864_driver_t* const drv)
{ {
max5864_spi_write(0x03); max5864_write(drv, 0x03);
} }
/* Set MAX5864 operation mode to "Xcvr": /* Set MAX5864 operation mode to "Xcvr":
@ -94,7 +96,7 @@ void max5864_tx()
* ADCs: on * ADCs: on
* DACs: on * DACs: on
*/ */
void max5864_xcvr() void max5864_xcvr(max5864_driver_t* const drv)
{ {
max5864_spi_write(0x04); max5864_write(drv, 0x04);
} }

View File

@ -22,11 +22,23 @@
#ifndef __MAX5864_H #ifndef __MAX5864_H
#define __MAX5864_H #define __MAX5864_H
void max5864_shutdown(); #include "spi_bus.h"
void max5864_standby();
void max5864_idle(); struct max5864_driver_t;
void max5864_rx(); typedef struct max5864_driver_t max5864_driver_t;
void max5864_tx();
void max5864_xcvr(); 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 #endif // __MAX5864_H

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "max5864_target.h"
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h"
void max5864_target_init(max5864_driver_t* const drv) {
(void)drv;
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */
scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
/*
* Configure CS_AD pin to keep the MAX5864 SPI disabled while we use the
* SPI bus for the MAX2837. FIXME: this should probably be somewhere else.
*/
scu_pinmux(SCU_AD_CS, SCU_GPIO_FAST);
}

View File

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

View File

@ -22,7 +22,6 @@
#include "rf_path.h" #include "rf_path.h"
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h> #include <libopencm3/lpc43xx/scu.h>
#include <hackrf_core.h> #include <hackrf_core.h>
@ -84,58 +83,58 @@ uint8_t switchctrl = SWITCHCTRL_SAFE;
#define SWITCHCTRL_ANT_PWR (1 << 6) /* turn on antenna port power */ #define SWITCHCTRL_ANT_PWR (1 << 6) /* turn on antenna port power */
#ifdef HACKRF_ONE #ifdef HACKRF_ONE
static void switchctrl_set_hackrf_one(uint8_t ctrl) { static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) {
if (ctrl & SWITCHCTRL_TX) { if (ctrl & SWITCHCTRL_TX) {
gpio_set(PORT_TX, PIN_TX); gpio_set(rf_path->gpio_tx);
gpio_clear(PORT_RX, PIN_RX); gpio_clear(rf_path->gpio_rx);
} else { } else {
gpio_clear(PORT_TX, PIN_TX); gpio_clear(rf_path->gpio_tx);
gpio_set(PORT_RX, PIN_RX); gpio_set(rf_path->gpio_rx);
} }
if (ctrl & SWITCHCTRL_MIX_BYPASS) { if (ctrl & SWITCHCTRL_MIX_BYPASS) {
gpio_set(PORT_MIX_BYPASS, PIN_MIX_BYPASS); gpio_set(rf_path->gpio_mix_bypass);
gpio_clear(PORT_NO_MIX_BYPASS, PIN_NO_MIX_BYPASS); gpio_clear(rf_path->gpio_no_mix_bypass);
if (ctrl & SWITCHCTRL_TX) { if (ctrl & SWITCHCTRL_TX) {
gpio_set(PORT_TX_MIX_BP, PIN_TX_MIX_BP); gpio_set(rf_path->gpio_tx_mix_bp);
gpio_clear(PORT_RX_MIX_BP, PIN_RX_MIX_BP); gpio_clear(rf_path->gpio_rx_mix_bp);
} else { } else {
gpio_clear(PORT_TX_MIX_BP, PIN_TX_MIX_BP); gpio_clear(rf_path->gpio_tx_mix_bp);
gpio_set(PORT_RX_MIX_BP, PIN_RX_MIX_BP); gpio_set(rf_path->gpio_rx_mix_bp);
} }
} else { } else {
gpio_clear(PORT_MIX_BYPASS, PIN_MIX_BYPASS); gpio_clear(rf_path->gpio_mix_bypass);
gpio_set(PORT_NO_MIX_BYPASS, PIN_NO_MIX_BYPASS); gpio_set(rf_path->gpio_no_mix_bypass);
gpio_clear(PORT_TX_MIX_BP, PIN_TX_MIX_BP); gpio_clear(rf_path->gpio_tx_mix_bp);
gpio_clear(PORT_RX_MIX_BP, PIN_RX_MIX_BP); gpio_clear(rf_path->gpio_rx_mix_bp);
} }
if (ctrl & SWITCHCTRL_HP) { if (ctrl & SWITCHCTRL_HP) {
gpio_set(PORT_HP, PIN_HP); gpio_set(rf_path->gpio_hp);
gpio_clear(PORT_LP, PIN_LP); gpio_clear(rf_path->gpio_lp);
} else { } else {
gpio_clear(PORT_HP, PIN_HP); gpio_clear(rf_path->gpio_hp);
gpio_set(PORT_LP, PIN_LP); gpio_set(rf_path->gpio_lp);
} }
if (ctrl & SWITCHCTRL_AMP_BYPASS) { if (ctrl & SWITCHCTRL_AMP_BYPASS) {
gpio_set(PORT_AMP_BYPASS, PIN_AMP_BYPASS); gpio_set(rf_path->gpio_amp_bypass);
gpio_clear(PORT_TX_AMP, PIN_TX_AMP); gpio_clear(rf_path->gpio_tx_amp);
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR); gpio_set(rf_path->gpio_no_tx_amp_pwr);
gpio_clear(PORT_RX_AMP, PIN_RX_AMP); gpio_clear(rf_path->gpio_rx_amp);
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR); gpio_set(rf_path->gpio_no_rx_amp_pwr);
} else if (ctrl & SWITCHCTRL_TX) { } else if (ctrl & SWITCHCTRL_TX) {
gpio_clear(PORT_AMP_BYPASS, PIN_AMP_BYPASS); gpio_clear(rf_path->gpio_amp_bypass);
gpio_set(PORT_TX_AMP, PIN_TX_AMP); gpio_set(rf_path->gpio_tx_amp);
gpio_clear(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR); gpio_clear(rf_path->gpio_no_tx_amp_pwr);
gpio_clear(PORT_RX_AMP, PIN_RX_AMP); gpio_clear(rf_path->gpio_rx_amp);
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR); gpio_set(rf_path->gpio_no_rx_amp_pwr);
} else { } else {
gpio_clear(PORT_AMP_BYPASS, PIN_AMP_BYPASS); gpio_clear(rf_path->gpio_amp_bypass);
gpio_clear(PORT_TX_AMP, PIN_TX_AMP); gpio_clear(rf_path->gpio_tx_amp);
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR); gpio_set(rf_path->gpio_no_tx_amp_pwr);
gpio_set(PORT_RX_AMP, PIN_RX_AMP); gpio_set(rf_path->gpio_rx_amp);
gpio_clear(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR); gpio_clear(rf_path->gpio_no_rx_amp_pwr);
} }
/* /*
@ -144,29 +143,29 @@ static void switchctrl_set_hackrf_one(uint8_t ctrl) {
* is unset: * is unset:
*/ */
if (ctrl & SWITCHCTRL_NO_TX_AMP_PWR) if (ctrl & SWITCHCTRL_NO_TX_AMP_PWR)
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR); gpio_set(rf_path->gpio_no_tx_amp_pwr);
if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR) if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR)
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR); gpio_set(rf_path->gpio_no_rx_amp_pwr);
if (ctrl & SWITCHCTRL_ANT_PWR) { if (ctrl & SWITCHCTRL_ANT_PWR) {
rffc5071_set_gpo(0x00); /* turn on antenna power by clearing GPO1 */ rffc5071_set_gpo(&rffc5072, 0x00); /* turn on antenna power by clearing GPO1 */
} else { } else {
rffc5071_set_gpo(0x01); /* turn off antenna power by setting GPO1 */ rffc5071_set_gpo(&rffc5072, 0x01); /* turn off antenna power by setting GPO1 */
} }
} }
#endif #endif
static void switchctrl_set(const uint8_t gpo) { static void switchctrl_set(rf_path_t* const rf_path, const uint8_t gpo) {
#ifdef JAWBREAKER #ifdef JAWBREAKER
rffc5071_set_gpo(gpo); rffc5071_set_gpo(&rffc5072, gpo);
#elif HACKRF_ONE #elif HACKRF_ONE
switchctrl_set_hackrf_one(gpo); switchctrl_set_hackrf_one(rf_path, gpo);
#else #else
(void)gpo; (void)gpo;
#endif #endif
} }
void rf_path_pin_setup() { void rf_path_pin_setup(rf_path_t* const rf_path) {
#ifdef HACKRF_ONE #ifdef HACKRF_ONE
/* Configure RF switch control signals */ /* Configure RF switch control signals */
scu_pinmux(SCU_HP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_HP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
@ -187,149 +186,152 @@ void rf_path_pin_setup() {
scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0); scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
/* Configure RF switch control signals as outputs */ /* Configure RF switch control signals as outputs */
GPIO0_DIR |= PIN_AMP_BYPASS; gpio_output(rf_path->gpio_amp_bypass);
GPIO1_DIR |= (PIN_NO_MIX_BYPASS | PIN_RX_AMP | PIN_NO_RX_AMP_PWR); gpio_output(rf_path->gpio_no_mix_bypass);
GPIO2_DIR |= (PIN_HP | PIN_LP | PIN_TX_MIX_BP | PIN_RX_MIX_BP | PIN_TX_AMP); gpio_output(rf_path->gpio_rx_amp);
GPIO3_DIR |= PIN_NO_TX_AMP_PWR; gpio_output(rf_path->gpio_no_rx_amp_pwr);
GPIO5_DIR |= (PIN_TX | PIN_MIX_BYPASS | PIN_RX); 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 * Safe (initial) switch settings turn off both amplifiers and antenna port
* power and enable both amp bypass and mixer bypass. * power and enable both amp bypass and mixer bypass.
*/ */
switchctrl_set(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS); switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS);
/* Configure RF power supply (VAA) switch control signal as output */
GPIO_DIR(PORT_NO_VAA_ENABLE) |= PIN_NO_VAA_ENABLE;
/* Safe state: start with VAA turned off: */
disable_rf_power();
#endif #endif
} }
void rf_path_init(void) { void rf_path_init(rf_path_t* const rf_path) {
ssp1_set_mode_max5864(); ssp1_set_mode_max5864();
max5864_shutdown(); max5864_setup(&max5864);
max5864_shutdown(&max5864);
ssp1_set_mode_max2837(); ssp1_set_mode_max2837();
max2837_setup(); max2837_setup(&max2837);
max2837_start(); max2837_start(&max2837);
rffc5071_setup(); rffc5071_setup(&rffc5072);
switchctrl_set(switchctrl); switchctrl_set(rf_path, switchctrl);
} }
void rf_path_set_direction(const rf_path_direction_t direction) { 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. */ /* Turn off TX and RX amplifiers, then enable based on direction and bypass state. */
switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR; rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
switch(direction) { switch(direction) {
case RF_PATH_DIRECTION_TX: case RF_PATH_DIRECTION_TX:
switchctrl |= SWITCHCTRL_TX; rf_path->switchctrl |= SWITCHCTRL_TX;
if( (switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) { if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
/* TX amplifier is in path, be sure to enable TX amplifier. */ /* TX amplifier is in path, be sure to enable TX amplifier. */
switchctrl &= ~SWITCHCTRL_NO_TX_AMP_PWR; rf_path->switchctrl &= ~SWITCHCTRL_NO_TX_AMP_PWR;
} }
rffc5071_tx(); rffc5071_tx(&rffc5072);
if( switchctrl & SWITCHCTRL_MIX_BYPASS ) { if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
rffc5071_disable(); rffc5071_disable(&rffc5072);
} else { } else {
rffc5071_enable(); rffc5071_enable(&rffc5072);
} }
ssp1_set_mode_max5864(); ssp1_set_mode_max5864();
max5864_tx(); max5864_tx(&max5864);
ssp1_set_mode_max2837(); ssp1_set_mode_max2837();
max2837_tx(); max2837_tx(&max2837);
sgpio_configure(SGPIO_DIRECTION_TX); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX);
break; break;
case RF_PATH_DIRECTION_RX: case RF_PATH_DIRECTION_RX:
switchctrl &= ~SWITCHCTRL_TX; rf_path->switchctrl &= ~SWITCHCTRL_TX;
if( (switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) { if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
/* RX amplifier is in path, be sure to enable RX amplifier. */ /* RX amplifier is in path, be sure to enable RX amplifier. */
switchctrl &= ~SWITCHCTRL_NO_RX_AMP_PWR; rf_path->switchctrl &= ~SWITCHCTRL_NO_RX_AMP_PWR;
} }
rffc5071_rx(); rffc5071_rx(&rffc5072);
if( switchctrl & SWITCHCTRL_MIX_BYPASS ) { if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
rffc5071_disable(); rffc5071_disable(&rffc5072);
} else { } else {
rffc5071_enable(); rffc5071_enable(&rffc5072);
} }
ssp1_set_mode_max5864(); ssp1_set_mode_max5864();
max5864_rx(); max5864_rx(&max5864);
ssp1_set_mode_max2837(); ssp1_set_mode_max2837();
max2837_rx(); max2837_rx(&max2837);
sgpio_configure(SGPIO_DIRECTION_RX); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
break; break;
case RF_PATH_DIRECTION_OFF: case RF_PATH_DIRECTION_OFF:
default: default:
#ifdef HACKRF_ONE #ifdef HACKRF_ONE
rf_path_set_antenna(0); rf_path_set_antenna(rf_path, 0);
#endif #endif
rf_path_set_lna(0); rf_path_set_lna(0);
/* Set RF path to receive direction when "off" */ /* Set RF path to receive direction when "off" */
switchctrl &= ~SWITCHCTRL_TX; rf_path->switchctrl &= ~SWITCHCTRL_TX;
rffc5071_disable(); rffc5071_disable(&rffc5072);
ssp1_set_mode_max5864(); ssp1_set_mode_max5864();
max5864_standby(); max5864_standby(&max5864);
ssp1_set_mode_max2837(); ssp1_set_mode_max2837();
max2837_set_mode(MAX2837_MODE_STANDBY); max2837_set_mode(&max2837, MAX2837_MODE_STANDBY);
sgpio_configure(SGPIO_DIRECTION_RX); sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
break; break;
} }
switchctrl_set(switchctrl); switchctrl_set(rf_path, rf_path->switchctrl);
} }
void rf_path_set_filter(const rf_path_filter_t filter) { void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) {
switch(filter) { switch(filter) {
default: default:
case RF_PATH_FILTER_BYPASS: case RF_PATH_FILTER_BYPASS:
switchctrl |= SWITCHCTRL_MIX_BYPASS; rf_path->switchctrl |= SWITCHCTRL_MIX_BYPASS;
rffc5071_disable(); rffc5071_disable(&rffc5072);
break; break;
case RF_PATH_FILTER_LOW_PASS: case RF_PATH_FILTER_LOW_PASS:
switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS); rf_path->switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
rffc5071_enable(); rffc5071_enable(&rffc5072);
break; break;
case RF_PATH_FILTER_HIGH_PASS: case RF_PATH_FILTER_HIGH_PASS:
switchctrl &= ~SWITCHCTRL_MIX_BYPASS; rf_path->switchctrl &= ~SWITCHCTRL_MIX_BYPASS;
switchctrl |= SWITCHCTRL_HP; rf_path->switchctrl |= SWITCHCTRL_HP;
rffc5071_enable(); rffc5071_enable(&rffc5072);
break; break;
} }
switchctrl_set(switchctrl); switchctrl_set(rf_path, rf_path->switchctrl);
} }
void rf_path_set_lna(const uint_fast8_t enable) { void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable) {
if( enable ) { if( enable ) {
if( switchctrl & SWITCHCTRL_TX ) { if( rf_path->switchctrl & SWITCHCTRL_TX ) {
/* AMP_BYPASS=0, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=0 */ /* AMP_BYPASS=0, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=0 */
switchctrl |= SWITCHCTRL_NO_RX_AMP_PWR; rf_path->switchctrl |= SWITCHCTRL_NO_RX_AMP_PWR;
switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR); rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR);
} else { } else {
/* AMP_BYPASS=0, NO_RX_AMP_PWR=0, NO_TX_AMP_PWR=1 */ /* AMP_BYPASS=0, NO_RX_AMP_PWR=0, NO_TX_AMP_PWR=1 */
switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR; rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR;
switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_RX_AMP_PWR); rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_RX_AMP_PWR);
} }
} else { } else {
/* AMP_BYPASS=1, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=1 */ /* AMP_BYPASS=1, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=1 */
switchctrl |= SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR; rf_path->switchctrl |= SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
} }
switchctrl_set(switchctrl); switchctrl_set(rf_path, rf_path->switchctrl);
} }
/* antenna port power control */ /* antenna port power control */
void rf_path_set_antenna(const uint_fast8_t enable) { void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable) {
if (enable) { if (enable) {
switchctrl |= SWITCHCTRL_ANT_PWR; rf_path->switchctrl |= SWITCHCTRL_ANT_PWR;
} else { } else {
switchctrl &= ~(SWITCHCTRL_ANT_PWR); rf_path->switchctrl &= ~(SWITCHCTRL_ANT_PWR);
} }
switchctrl_set(switchctrl); switchctrl_set(rf_path, rf_path->switchctrl);
} }

View File

@ -25,8 +25,7 @@
#include <stdint.h> #include <stdint.h>
void rf_path_pin_setup(void); #include "gpio.h"
void rf_path_init(void);
typedef enum { typedef enum {
RF_PATH_DIRECTION_OFF, RF_PATH_DIRECTION_OFF,
@ -34,17 +33,39 @@ typedef enum {
RF_PATH_DIRECTION_TX, RF_PATH_DIRECTION_TX,
} rf_path_direction_t; } rf_path_direction_t;
void rf_path_set_direction(const rf_path_direction_t direction);
typedef enum { typedef enum {
RF_PATH_FILTER_BYPASS = 0, RF_PATH_FILTER_BYPASS = 0,
RF_PATH_FILTER_LOW_PASS = 1, RF_PATH_FILTER_LOW_PASS = 1,
RF_PATH_FILTER_HIGH_PASS = 2, RF_PATH_FILTER_HIGH_PASS = 2,
} rf_path_filter_t; } rf_path_filter_t;
void rf_path_set_filter(const rf_path_filter_t filter); 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
} rf_path_t;
void rf_path_set_lna(const uint_fast8_t enable); void rf_path_pin_setup(rf_path_t* const rf_path);
void rf_path_set_antenna(const uint_fast8_t enable); 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__*/ #endif/*__RFPATH_H__*/

View File

@ -36,19 +36,10 @@
#include "rffc5071.h" #include "rffc5071.h"
#include "rffc5071_regs.def" // private register def macros #include "rffc5071_regs.def" // private register def macros
#if (defined DEBUG)
#include <stdio.h>
#define LOG printf
#else
#define LOG(x,...)
#include <libopencm3/lpc43xx/ssp.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/gpio.h>
#include "hackrf_core.h" #include "hackrf_core.h"
#endif
/* Default register values. */ /* Default register values. */
static uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = { static const uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = {
0xbefa, /* 00 */ 0xbefa, /* 00 */
0x4064, /* 01 */ 0x4064, /* 01 */
0x9055, /* 02 */ 0x9055, /* 02 */
@ -81,327 +72,139 @@ static uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = {
0x1000, /* 1D */ 0x1000, /* 1D */
0x0005, /* 1E */ }; 0x0005, /* 1E */ };
uint16_t rffc5071_regs[RFFC5071_NUM_REGS];
/* Mark all regsisters dirty so all will be written at init. */
uint32_t rffc5071_regs_dirty = 0x7fffffff;
/* Set up all registers according to defaults specified in docs. */ /* Set up all registers according to defaults specified in docs. */
void rffc5071_init(void) void rffc5071_init(rffc5071_driver_t* const drv)
{ {
LOG("# rffc5071_init\n"); memcpy(drv->regs, rffc5071_regs_default, sizeof(drv->regs));
memcpy(rffc5071_regs, rffc5071_regs_default, sizeof(rffc5071_regs)); drv->regs_dirty = 0x7fffffff;
rffc5071_regs_dirty = 0x7fffffff;
/* Write default register values to chip. */ /* Write default register values to chip. */
rffc5071_regs_commit(); rffc5071_regs_commit(drv);
} }
/* /*
* Set up pins for GPIO and SPI control, configure SSP peripheral for SPI, and * Set up pins for GPIO and SPI control, configure SSP peripheral for SPI, and
* set our own default register configuration. * set our own default register configuration.
*/ */
void rffc5071_setup(void) void rffc5071_setup(rffc5071_driver_t* const drv)
{ {
rffc5071_init(); gpio_set(drv->gpio_reset);
LOG("# rffc5071_setup\n"); gpio_output(drv->gpio_reset);
#if !defined TEST
/* Configure GPIO pins. */
scu_pinmux(SCU_MIXER_ENX, SCU_GPIO_FAST);
scu_pinmux(SCU_MIXER_SCLK, SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
scu_pinmux(SCU_MIXER_SDATA, SCU_GPIO_FAST);
scu_pinmux(SCU_MIXER_RESETX, SCU_GPIO_FAST);
/* Set GPIO pins as outputs. */ rffc5071_init(drv);
GPIO_DIR(PORT_MIXER_ENX) |= PIN_MIXER_ENX;
GPIO_DIR(PORT_MIXER_SCLK) |= PIN_MIXER_SCLK;
GPIO_DIR(PORT_MIXER_SDATA) |= PIN_MIXER_SDATA;
GPIO_DIR(PORT_MIXER_RESETX) |= PIN_MIXER_RESETX;
/* set to known state */
gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX); /* active low */
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA);
gpio_set(PORT_MIXER_RESETX, PIN_MIXER_RESETX); /* active low */
#endif
/* initial setup */ /* initial setup */
/* put zeros in freq contol registers */ /* put zeros in freq contol registers */
set_RFFC5071_P2N(0); set_RFFC5071_P2N(drv, 0);
set_RFFC5071_P2LODIV(0); set_RFFC5071_P2LODIV(drv, 0);
set_RFFC5071_P2PRESC(0); set_RFFC5071_P2PRESC(drv, 0);
set_RFFC5071_P2VCOSEL(0); set_RFFC5071_P2VCOSEL(drv, 0);
set_RFFC5071_P2N(0); set_RFFC5071_P2N(drv, 0);
set_RFFC5071_P2LODIV(0); set_RFFC5071_P2LODIV(drv, 0);
set_RFFC5071_P2PRESC(0); set_RFFC5071_P2PRESC(drv, 0);
set_RFFC5071_P2VCOSEL(0); set_RFFC5071_P2VCOSEL(drv, 0);
set_RFFC5071_P2N(0); set_RFFC5071_P2N(drv, 0);
set_RFFC5071_P2LODIV(0); set_RFFC5071_P2LODIV(drv, 0);
set_RFFC5071_P2PRESC(0); set_RFFC5071_P2PRESC(drv, 0);
set_RFFC5071_P2VCOSEL(0); set_RFFC5071_P2VCOSEL(drv, 0);
/* set ENBL and MODE to be configured via 3-wire interface, /* set ENBL and MODE to be configured via 3-wire interface,
* not control pins. */ * not control pins. */
set_RFFC5071_SIPIN(1); set_RFFC5071_SIPIN(drv, 1);
/* GPOs are active at all times */ /* GPOs are active at all times */
set_RFFC5071_GATE(1); set_RFFC5071_GATE(drv, 1);
rffc5071_regs_commit(); rffc5071_regs_commit(drv);
} }
void serial_delay(void) static uint16_t rffc5071_spi_read(rffc5071_driver_t* const drv, uint8_t r) {
{ (void)drv;
uint32_t i;
for (i = 0; i < 2; i++) uint16_t data[] = { 0x80 | (r & 0x7f), 0xffff };
__asm__("nop"); spi_bus_transfer(drv->bus, data, 2);
return data[1];
} }
/* SPI register read. static void rffc5071_spi_write(rffc5071_driver_t* const drv, uint8_t r, uint16_t v) {
* (void)drv;
* 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).
*/
uint16_t rffc5071_spi_read(uint8_t r) {
int bits = 9; uint16_t data[] = { 0x00 | (r & 0x7f), v };
int msb = 1 << (bits -1); spi_bus_transfer(drv->bus, data, 2);
uint32_t data = 0x80 | (r & 0x7f);
#if DEBUG
LOG("reg%d = 0\n", r);
return 0;
#else
/* make sure everything is starting in the correct state */
gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX);
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA);
/*
* The device requires two clocks while ENX is high before a serial
* transaction. This is not clearly documented.
*/
serial_delay();
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
/* start transaction by bringing ENX low */
gpio_clear(PORT_MIXER_ENX, PIN_MIXER_ENX);
while (bits--) {
if (data & msb)
gpio_set(PORT_MIXER_SDATA, PIN_MIXER_SDATA);
else
gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA);
data <<= 1;
serial_delay();
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
} }
serial_delay(); uint16_t rffc5071_reg_read(rffc5071_driver_t* const drv, uint8_t r)
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
bits = 16;
data = 0;
/* set SDATA line as input */
GPIO_DIR(PORT_MIXER_SDATA) &= ~PIN_MIXER_SDATA;
while (bits--) {
data <<= 1;
serial_delay();
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
if (MIXER_SDATA_STATE)
data |= 1;
}
/* set SDATA line as output */
GPIO_DIR(PORT_MIXER_SDATA) |= PIN_MIXER_SDATA;
serial_delay();
gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX);
/*
* The device requires a clock while ENX is high after a serial
* transaction. This is not clearly documented.
*/
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
return data;
#endif /* DEBUG */
}
/* 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_write(uint8_t r, uint16_t v) {
#if DEBUG
LOG("0x%04x -> reg%d\n", v, r);
#else
int bits = 25;
int msb = 1 << (bits -1);
uint32_t data = ((r & 0x7f) << 16) | v;
/* make sure everything is starting in the correct state */
gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX);
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA);
/*
* The device requires two clocks while ENX is high before a serial
* transaction. This is not clearly documented.
*/
serial_delay();
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
/* start transaction by bringing ENX low */
gpio_clear(PORT_MIXER_ENX, PIN_MIXER_ENX);
while (bits--) {
if (data & msb)
gpio_set(PORT_MIXER_SDATA, PIN_MIXER_SDATA);
else
gpio_clear(PORT_MIXER_SDATA, PIN_MIXER_SDATA);
data <<= 1;
serial_delay();
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
}
gpio_set(PORT_MIXER_ENX, PIN_MIXER_ENX);
/*
* The device requires a clock while ENX is high after a serial
* transaction. This is not clearly documented.
*/
serial_delay();
gpio_set(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
serial_delay();
gpio_clear(PORT_MIXER_SCLK, PIN_MIXER_SCLK);
#endif
}
uint16_t rffc5071_reg_read(uint8_t r)
{ {
/* Readback register is not cached. */ /* Readback register is not cached. */
if (r == RFFC5071_READBACK_REG) if (r == RFFC5071_READBACK_REG)
return rffc5071_spi_read(r); return rffc5071_spi_read(drv, r);
/* Discard uncommited write when reading. This shouldn't /* Discard uncommited write when reading. This shouldn't
* happen, and probably has not been tested. */ * happen, and probably has not been tested. */
if ((rffc5071_regs_dirty >> r) & 0x1) { if ((drv->regs_dirty >> r) & 0x1) {
rffc5071_regs[r] = rffc5071_spi_read(r); drv->regs[r] = rffc5071_spi_read(drv, r);
}; };
return rffc5071_regs[r]; return drv->regs[r];
} }
void rffc5071_reg_write(uint8_t r, uint16_t v) void rffc5071_reg_write(rffc5071_driver_t* const drv, uint8_t r, uint16_t v)
{ {
rffc5071_regs[r] = v; drv->regs[r] = v;
rffc5071_spi_write(r, v); rffc5071_spi_write(drv, r, v);
RFFC5071_REG_SET_CLEAN(r); RFFC5071_REG_SET_CLEAN(drv, r);
} }
static inline void rffc5071_reg_commit(uint8_t r) static inline void rffc5071_reg_commit(rffc5071_driver_t* const drv, uint8_t r)
{ {
rffc5071_reg_write(r,rffc5071_regs[r]); rffc5071_reg_write(drv, r, drv->regs[r]);
} }
void rffc5071_regs_commit(void) void rffc5071_regs_commit(rffc5071_driver_t* const drv)
{ {
int r; int r;
for(r = 0; r < RFFC5071_NUM_REGS; r++) { for(r = 0; r < RFFC5071_NUM_REGS; r++) {
if ((rffc5071_regs_dirty >> r) & 0x1) { if ((drv->regs_dirty >> r) & 0x1) {
rffc5071_reg_commit(r); rffc5071_reg_commit(drv, r);
} }
} }
} }
void rffc5071_tx(void) { void rffc5071_tx(rffc5071_driver_t* const drv) {
LOG("# rffc5071_tx\n"); set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_ENBL(0); set_RFFC5071_FULLD(drv, 0);
set_RFFC5071_FULLD(0); set_RFFC5071_MODE(drv, 1); /* mixer 2 used for both RX and TX */
set_RFFC5071_MODE(1); /* mixer 2 used for both RX and TX */ rffc5071_regs_commit(drv);
rffc5071_regs_commit();
} }
void rffc5071_rx(void) { void rffc5071_rx(rffc5071_driver_t* const drv) {
LOG("# rfc5071_rx\n"); set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_ENBL(0); set_RFFC5071_FULLD(drv, 0);
set_RFFC5071_FULLD(0); set_RFFC5071_MODE(drv, 1); /* mixer 2 used for both RX and TX */
set_RFFC5071_MODE(1); /* mixer 2 used for both RX and TX */ rffc5071_regs_commit(drv);
rffc5071_regs_commit();
} }
/* /*
* This function turns on both mixer (full-duplex) on the RFFC5071, but our * This function turns on both mixer (full-duplex) on the RFFC5071, but our
* current hardware designs do not support full-duplex operation. * current hardware designs do not support full-duplex operation.
*/ */
void rffc5071_rxtx(void) { void rffc5071_rxtx(rffc5071_driver_t* const drv) {
LOG("# rfc5071_rxtx\n"); set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_ENBL(0); set_RFFC5071_FULLD(drv, 1); /* mixer 1 and mixer 2 (RXTX) */
set_RFFC5071_FULLD(1); /* mixer 1 and mixer 2 (RXTX) */ rffc5071_regs_commit(drv);
rffc5071_regs_commit();
rffc5071_enable(); rffc5071_enable(drv);
} }
void rffc5071_disable(void) { void rffc5071_disable(rffc5071_driver_t* const drv) {
LOG("# rfc5071_disable\n"); set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_ENBL(0); rffc5071_regs_commit(drv);
rffc5071_regs_commit();
} }
void rffc5071_enable(void) { void rffc5071_enable(rffc5071_driver_t* const drv) {
LOG("# rfc5071_enable\n"); set_RFFC5071_ENBL(drv, 1);
set_RFFC5071_ENBL(1); rffc5071_regs_commit(drv);
rffc5071_regs_commit();
} }
#define LO_MAX 5400 #define LO_MAX 5400
@ -409,7 +212,7 @@ void rffc5071_enable(void) {
#define FREQ_ONE_MHZ (1000*1000) #define FREQ_ONE_MHZ (1000*1000)
/* configure frequency synthesizer in integer mode (lo in MHz) */ /* configure frequency synthesizer in integer mode (lo in MHz) */
uint64_t rffc5071_config_synth_int(uint16_t lo) { uint64_t rffc5071_config_synth_int(rffc5071_driver_t* const drv, uint16_t lo) {
uint8_t lodiv; uint8_t lodiv;
uint16_t fvco; uint16_t fvco;
uint8_t fbkdiv; uint8_t fbkdiv;
@ -418,8 +221,6 @@ uint64_t rffc5071_config_synth_int(uint16_t lo) {
uint16_t p1nmsb; uint16_t p1nmsb;
uint8_t p1nlsb; uint8_t p1nlsb;
LOG("# config_synth_int\n");
/* Calculate n_lo */ /* Calculate n_lo */
uint8_t n_lo = 0; uint8_t n_lo = 0;
uint16_t x = LO_MAX / lo; uint16_t x = LO_MAX / lo;
@ -438,10 +239,10 @@ uint64_t rffc5071_config_synth_int(uint16_t lo) {
* and will be unaffected. */ * and will be unaffected. */
if (fvco > 3200) { if (fvco > 3200) {
fbkdiv = 4; fbkdiv = 4;
set_RFFC5071_PLLCPL(3); set_RFFC5071_PLLCPL(drv, 3);
} else { } else {
fbkdiv = 2; fbkdiv = 2;
set_RFFC5071_PLLCPL(2); set_RFFC5071_PLLCPL(drv, 2);
} }
uint64_t tmp_n = ((uint64_t)fvco << 29ULL) / (fbkdiv*REF_FREQ) ; uint64_t tmp_n = ((uint64_t)fvco << 29ULL) / (fbkdiv*REF_FREQ) ;
@ -452,63 +253,42 @@ uint64_t rffc5071_config_synth_int(uint16_t lo) {
tune_freq_hz = (REF_FREQ * (tmp_n >> 5ULL) * fbkdiv * FREQ_ONE_MHZ) tune_freq_hz = (REF_FREQ * (tmp_n >> 5ULL) * fbkdiv * FREQ_ONE_MHZ)
/ (lodiv * (1 << 24ULL)); / (lodiv * (1 << 24ULL));
LOG("# lo=%d n_lo=%d lodiv=%d fvco=%d fbkdiv=%d n=%d tune_freq_hz=%d\n",
lo, n_lo, lodiv, fvco, fbkdiv, n, tune_freq);
/* Path 1 */ /* Path 1 */
set_RFFC5071_P1LODIV(n_lo); set_RFFC5071_P1LODIV(drv, n_lo);
set_RFFC5071_P1N(n); set_RFFC5071_P1N(drv, n);
set_RFFC5071_P1PRESC(fbkdiv >> 1); set_RFFC5071_P1PRESC(drv, fbkdiv >> 1);
set_RFFC5071_P1NMSB(p1nmsb); set_RFFC5071_P1NMSB(drv, p1nmsb);
set_RFFC5071_P1NLSB(p1nlsb); set_RFFC5071_P1NLSB(drv, p1nlsb);
/* Path 2 */ /* Path 2 */
set_RFFC5071_P2LODIV(n_lo); set_RFFC5071_P2LODIV(drv, n_lo);
set_RFFC5071_P2N(n); set_RFFC5071_P2N(drv, n);
set_RFFC5071_P2PRESC(fbkdiv >> 1); set_RFFC5071_P2PRESC(drv, fbkdiv >> 1);
set_RFFC5071_P2NMSB(p1nmsb); set_RFFC5071_P2NMSB(drv, p1nmsb);
set_RFFC5071_P2NLSB(p1nlsb); set_RFFC5071_P2NLSB(drv, p1nlsb);
rffc5071_regs_commit(); rffc5071_regs_commit(drv);
return tune_freq_hz; return tune_freq_hz;
} }
/* !!!!!!!!!!! hz is currently ignored !!!!!!!!!!! */ /* !!!!!!!!!!! hz is currently ignored !!!!!!!!!!! */
uint64_t rffc5071_set_frequency(uint16_t mhz) { uint64_t rffc5071_set_frequency(rffc5071_driver_t* const drv, uint16_t mhz) {
uint32_t tune_freq; uint32_t tune_freq;
rffc5071_disable(); rffc5071_disable(drv);
tune_freq = rffc5071_config_synth_int(mhz); tune_freq = rffc5071_config_synth_int(drv, mhz);
rffc5071_enable(); rffc5071_enable(drv);
return tune_freq; return tune_freq;
} }
void rffc5071_set_gpo(uint8_t gpo) void rffc5071_set_gpo(rffc5071_driver_t* const drv, uint8_t gpo)
{ {
/* We set GPO for both paths just in case. */ /* We set GPO for both paths just in case. */
set_RFFC5071_P1GPO(gpo); set_RFFC5071_P1GPO(drv, gpo);
set_RFFC5071_P2GPO(gpo); set_RFFC5071_P2GPO(drv, gpo);
rffc5071_regs_commit(); rffc5071_regs_commit(drv);
} }
#ifdef TEST
int main(int ac, char **av)
{
rffc5071_setup();
rffc5071_tx(0);
rffc5071_set_frequency(500, 0);
rffc5071_set_frequency(525, 0);
rffc5071_set_frequency(550, 0);
rffc5071_set_frequency(1500, 0);
rffc5071_set_frequency(1525, 0);
rffc5071_set_frequency(1550, 0);
rffc5071_disable();
rffc5071_rx(0);
rffc5071_disable();
rffc5071_rxtx();
rffc5071_disable();
}
#endif //TEST

View File

@ -23,43 +23,49 @@
#ifndef __RFFC5071_H #ifndef __RFFC5071_H
#define __RFFC5071_H #define __RFFC5071_H
#include <stdint.h>
#include "spi_bus.h"
#include "gpio.h"
/* 31 registers, each containing 16 bits of data. */ /* 31 registers, each containing 16 bits of data. */
#define RFFC5071_NUM_REGS 31 #define RFFC5071_NUM_REGS 31
extern uint16_t rffc5071_regs[RFFC5071_NUM_REGS]; typedef struct {
extern uint32_t rffc5071_regs_dirty; spi_bus_t* const bus;
gpio_t gpio_reset;
#define RFFC5071_REG_SET_CLEAN(r) rffc5071_regs_dirty &= ~(1UL<<r) uint16_t regs[RFFC5071_NUM_REGS];
#define RFFC5071_REG_SET_DIRTY(r) rffc5071_regs_dirty |= (1UL<<r) uint32_t regs_dirty;
} rffc5071_driver_t;
/* Initialize chip. Call _setup() externally, as it calls _init(). */ /* Initialize chip. Call _setup() externally, as it calls _init(). */
extern void rffc5071_init(void); extern void rffc5071_init(rffc5071_driver_t* const drv);
extern void rffc5071_setup(void); extern void rffc5071_setup(rffc5071_driver_t* const drv);
/* Read a register via SPI. Save a copy to memory and return /* Read a register via SPI. Save a copy to memory and return
* value. Discard any uncommited changes and mark CLEAN. */ * value. Discard any uncommited changes and mark CLEAN. */
extern uint16_t rffc5071_reg_read(uint8_t r); 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 /* Write value to register via SPI and save a copy to memory. Mark
* CLEAN. */ * CLEAN. */
extern void rffc5071_reg_write(uint8_t r, uint16_t v); 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 /* Write all dirty registers via SPI from memory. Mark all clean. Some
* operations require registers to be written in a certain order. Use * operations require registers to be written in a certain order. Use
* provided routines for those operations. */ * provided routines for those operations. */
extern void rffc5071_regs_commit(void); extern void rffc5071_regs_commit(rffc5071_driver_t* const drv);
/* Set frequency (MHz). */ /* Set frequency (MHz). */
extern uint64_t rffc5071_set_frequency(uint16_t 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 /* Set up rx only, tx only, or full duplex. Chip should be disabled
* before _tx, _rx, or _rxtx are called. */ * before _tx, _rx, or _rxtx are called. */
extern void rffc5071_tx(void); extern void rffc5071_tx(rffc5071_driver_t* const drv);
extern void rffc5071_rx(void); extern void rffc5071_rx(rffc5071_driver_t* const drv);
extern void rffc5071_rxtx(void); extern void rffc5071_rxtx(rffc5071_driver_t* const drv);
extern void rffc5071_enable(void); extern void rffc5071_enable(rffc5071_driver_t* const drv);
extern void rffc5071_disable(void); extern void rffc5071_disable(rffc5071_driver_t* const drv);
extern void rffc5071_set_gpo(uint8_t); extern void rffc5071_set_gpo(rffc5071_driver_t* const drv, uint8_t);
#endif // __RFFC5071_H #endif // __RFFC5071_H

View File

@ -23,6 +23,9 @@
#ifndef __RFFC5071_REGS_DEF #ifndef __RFFC5071_REGS_DEF
#define __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 #define RFFC5071_READBACK_REG 31
/* Generate static inline accessors that operate on the global /* Generate static inline accessors that operate on the global
@ -38,13 +41,13 @@
/* n=name, r=regnum, o=offset (bits from LSB) of LSB of field, /* n=name, r=regnum, o=offset (bits from LSB) of LSB of field,
* l=length (bits) */ * l=length (bits) */
#define __MREG__(n,r,o,l) \ #define __MREG__(n,r,o,l) \
static inline uint16_t get_##n(void) { \ static inline uint16_t get_##n(rffc5071_driver_t* const _d) { \
return (rffc5071_regs[r] >> o) & ((1L<<l)-1); \ return (_d->regs[r] >> o) & ((1L<<l)-1); \
} \ } \
static inline void set_##n(uint16_t v) { \ static inline void set_##n(rffc5071_driver_t* const _d, uint16_t v) { \
rffc5071_regs[r] &= (uint16_t)(~(((1L<<l)-1)<<o)); \ _d->regs[r] &= (uint16_t)(~(((1L<<l)-1)<<o)); \
rffc5071_regs[r] |= (uint16_t)(((v&((1L<<l)-1))<<o)); \ _d->regs[r] |= (uint16_t)(((v&((1L<<l)-1))<<o)); \
RFFC5071_REG_SET_DIRTY(r); \ RFFC5071_REG_SET_DIRTY(_d, r); \
} }
/* REG 00 (0): LF */ /* REG 00 (0): LF */

View File

@ -0,0 +1,187 @@
/*
* 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;
volatile uint32_t i;
for (i = 0; i < 2; i++)
__asm__("nop");
}
static void rffc5071_spi_sck(spi_bus_t* const bus) {
const rffc5071_spi_config_t* const config = bus->config;
rffc5071_spi_serial_delay(bus);
gpio_set(config->gpio_clock);
rffc5071_spi_serial_delay(bus);
gpio_clear(config->gpio_clock);
}
static uint32_t rffc5071_spi_exchange_bit(spi_bus_t* const bus, const uint32_t bit) {
rffc5071_spi_data_out(bus, bit);
rffc5071_spi_sck(bus);
return rffc5071_spi_data_in(bus) ? 1 : 0;
}
static uint32_t rffc5071_spi_exchange_word(spi_bus_t* const bus, const uint32_t data, const size_t count) {
size_t bits = count;
const uint32_t msb = 1UL << (count - 1);
uint32_t t = data;
while (bits--) {
t = (t << 1) | rffc5071_spi_exchange_bit(bus, t & msb);
}
return t & ((1UL << count) - 1);
}
/* SPI register read.
*
* Send 9 bits:
* first bit is ignored,
* second bit is one for read operation,
* next 7 bits are register address.
* Then receive 16 bits (register value).
*/
/* SPI register write
*
* Send 25 bits:
* first bit is ignored,
* second bit is zero for write operation,
* next 7 bits are register address,
* next 16 bits are register value.
*/
void rffc5071_spi_transfer(spi_bus_t* const bus, void* const _data, const size_t count) {
if( count != 2 ) {
return;
}
uint16_t* const data = _data;
const bool direction_read = (data[0] >> 7) & 1;
/*
* The device requires two clocks while ENX is high before a serial
* transaction. This is not clearly documented.
*/
rffc5071_spi_sck(bus);
rffc5071_spi_sck(bus);
rffc5071_spi_target_select(bus);
data[0] = rffc5071_spi_exchange_word(bus, data[0], 9);
if( direction_read ) {
rffc5071_spi_direction_in(bus);
rffc5071_spi_sck(bus);
}
data[1] = rffc5071_spi_exchange_word(bus, data[1], 16);
rffc5071_spi_serial_delay(bus);
rffc5071_spi_target_unselect(bus);
rffc5071_spi_direction_out(bus);
/*
* The device requires a clock while ENX is high after a serial
* transaction. This is not clearly documented.
*/
rffc5071_spi_sck(bus);
}
void rffc5071_spi_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfer, const size_t count) {
if( count == 1 ) {
rffc5071_spi_transfer(bus, transfer[0].data, transfer[0].count);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2012 Michael Ossmann
* Copyright 2014 Jared Boone <jared@sharebrained.com>
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __RFFC5071_SPI_H
#define __RFFC5071_SPI_H
#include "spi_bus.h"
#include "gpio.h"
typedef struct rffc5071_spi_config_t {
gpio_t gpio_select;
gpio_t gpio_clock;
gpio_t gpio_data;
} rffc5071_spi_config_t;
void rffc5071_spi_start(spi_bus_t* const bus, const void* const config);
void rffc5071_spi_stop(spi_bus_t* const bus);
void rffc5071_spi_transfer(spi_bus_t* const bus, void* const data, const size_t count);
void rffc5071_spi_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfer, const size_t count);
#endif // __RFFC5071_SPI_H

View File

@ -77,7 +77,8 @@ isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res)
Alternative way to retrieve Part Id on MCU with no IAP Alternative way to retrieve Part Id on MCU with no IAP
Read Serial No => Read Unique ID in SPIFI (only compatible with W25Q80BV Read Serial No => Read Unique ID in SPIFI (only compatible with W25Q80BV
*/ */
w25q80bv_setup(); spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv);
w25q80bv_setup(&spi_flash);
switch(iap_cmd_res->cmd_param.command_code) switch(iap_cmd_res->cmd_param.command_code)
{ {
@ -92,7 +93,7 @@ isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res)
/* Only 64bits used */ /* Only 64bits used */
iap_cmd_res->status_res.iap_result[0] = 0; iap_cmd_res->status_res.iap_result[0] = 0;
iap_cmd_res->status_res.iap_result[1] = 0; iap_cmd_res->status_res.iap_result[1] = 0;
w25q80bv_get_unique_id( (w25q80bv_unique_id_t*)&iap_cmd_res->status_res.iap_result[2] ); 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; iap_cmd_res->status_res.status_ret = CMD_SUCCESS;
break; break;

View File

@ -20,7 +20,6 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h> #include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/sgpio.h> #include <libopencm3/lpc43xx/sgpio.h>
@ -28,9 +27,7 @@
#include <sgpio.h> #include <sgpio.h>
static bool sgpio_slice_mode_multislice = true; void sgpio_configure_pin_functions(sgpio_config_t* const config) {
void sgpio_configure_pin_functions() {
scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3); 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_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
scu_pinmux(SCU_PINMUX_SGPIO2, SCU_GPIO_FAST | SCU_CONF_FUNCTION2); scu_pinmux(SCU_PINMUX_SGPIO2, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
@ -48,61 +45,20 @@ void sgpio_configure_pin_functions() {
scu_pinmux(SCU_PINMUX_SGPIO14, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[13] */ 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] */ scu_pinmux(SCU_PINMUX_SGPIO15, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[14] */
sgpio_cpld_stream_rx_set_decimation(1); sgpio_cpld_stream_rx_set_decimation(config, 1);
sgpio_cpld_stream_rx_set_q_invert(0); sgpio_cpld_stream_rx_set_q_invert(config, 0);
GPIO_DIR(GPIO0) |= GPIOPIN13; gpio_output(config->gpio_rx_q_invert);
GPIO_DIR(GPIO5) |= GPIOPIN14 | GPIOPIN13 | GPIOPIN12; gpio_output(config->gpio_rx_decimation[0]);
} gpio_output(config->gpio_rx_decimation[1]);
gpio_output(config->gpio_rx_decimation[2]);
void sgpio_test_interface() {
const uint_fast8_t host_clock_sgpio_pin = 8; // Input
const uint_fast8_t host_capture_sgpio_pin = 9; // Input
const uint_fast8_t host_disable_sgpio_pin = 10; // Output
const uint_fast8_t host_direction_sgpio_pin = 11; // Output
SGPIO_GPIO_OENREG = 0; // All inputs for the moment.
// Disable all counters during configuration
SGPIO_CTRL_ENABLE = 0;
// Make all SGPIO controlled by SGPIO's "GPIO" registers
for (uint_fast8_t i = 0; i < 16; i++) {
SGPIO_OUT_MUX_CFG(i) =
SGPIO_OUT_MUX_CFG_P_OE_CFG(0)
| SGPIO_OUT_MUX_CFG_P_OUT_CFG(4);
}
// Set SGPIO output values.
SGPIO_GPIO_OUTREG =
(1L << host_direction_sgpio_pin)
| (1L << host_disable_sgpio_pin);
// Enable SGPIO pin outputs.
SGPIO_GPIO_OENREG =
(1L << host_direction_sgpio_pin)
| (1L << host_disable_sgpio_pin)
| (0L << host_capture_sgpio_pin)
| (0L << host_clock_sgpio_pin)
| (0xFF << 0);
// Configure SGPIO slices.
// Enable codec data stream.
SGPIO_GPIO_OUTREG &= ~(1L << host_disable_sgpio_pin);
while (1) {
for (uint_fast8_t i = 0; i < 8; i++) {
SGPIO_GPIO_OUTREG ^= (1L << i);
}
}
} }
void sgpio_set_slice_mode( void sgpio_set_slice_mode(
sgpio_config_t* const config,
const bool multi_slice const bool multi_slice
) { ) {
sgpio_slice_mode_multislice = multi_slice; config->slice_mode_multislice = multi_slice;
} }
/* /*
@ -118,6 +74,7 @@ void sgpio_set_slice_mode(
SGPIO11 Direction Output (1/High=TX mode LPC43xx=>CPLD=>DAC, 0/Low=RX mode LPC43xx<=CPLD<=ADC) SGPIO11 Direction Output (1/High=TX mode LPC43xx=>CPLD=>DAC, 0/Low=RX mode LPC43xx<=CPLD<=ADC)
*/ */
void sgpio_configure( void sgpio_configure(
sgpio_config_t* const config,
const sgpio_direction_t direction const sgpio_direction_t direction
) { ) {
// Disable all counters during configuration // Disable all counters during configuration
@ -167,7 +124,7 @@ void sgpio_configure(
; ;
const uint_fast8_t output_multiplexing_mode = const uint_fast8_t output_multiplexing_mode =
sgpio_slice_mode_multislice ? 11 : 9; config->slice_mode_multislice ? 11 : 9;
/* SGPIO0 to SGPIO7 */ /* SGPIO0 to SGPIO7 */
for(uint_fast8_t i=0; i<8; i++) { for(uint_fast8_t i=0; i<8; i++) {
// SGPIO pin 0 outputs slice A bit "i". // SGPIO pin 0 outputs slice A bit "i".
@ -189,9 +146,9 @@ void sgpio_configure(
}; };
const uint_fast8_t slice_gpdma = SGPIO_SLICE_H; const uint_fast8_t slice_gpdma = SGPIO_SLICE_H;
const uint_fast8_t pos = sgpio_slice_mode_multislice ? 0x1f : 0x03; const uint_fast8_t pos = config->slice_mode_multislice ? 0x1f : 0x03;
const bool single_slice = !sgpio_slice_mode_multislice; const bool single_slice = !config->slice_mode_multislice;
const uint_fast8_t slice_count = sgpio_slice_mode_multislice ? 8 : 1; const uint_fast8_t slice_count = config->slice_mode_multislice ? 8 : 1;
const uint_fast8_t clk_capture_mode = (direction == SGPIO_DIRECTION_TX) ? 0 : 1; const uint_fast8_t clk_capture_mode = (direction == SGPIO_DIRECTION_TX) ? 0 : 1;
uint32_t slice_enable_mask = 0; uint32_t slice_enable_mask = 0;
@ -236,7 +193,7 @@ void sgpio_configure(
slice_enable_mask |= (1 << slice_index); slice_enable_mask |= (1 << slice_index);
} }
if( sgpio_slice_mode_multislice == false ) { if( config->slice_mode_multislice == false ) {
SGPIO_MUX_CFG(slice_gpdma) = SGPIO_MUX_CFG(slice_gpdma) =
SGPIO_MUX_CFG_CONCAT_ORDER(0) /* Self-loop */ SGPIO_MUX_CFG_CONCAT_ORDER(0) /* Self-loop */
| SGPIO_MUX_CFG_CONCAT_ENABLE(1) | SGPIO_MUX_CFG_CONCAT_ENABLE(1)
@ -274,21 +231,24 @@ void sgpio_configure(
SGPIO_CTRL_ENABLE = slice_enable_mask; SGPIO_CTRL_ENABLE = slice_enable_mask;
} }
void sgpio_cpld_stream_enable() { void sgpio_cpld_stream_enable(sgpio_config_t* const config) {
(void)config;
// Enable codec data stream. // Enable codec data stream.
SGPIO_GPIO_OUTREG &= ~(1L << 10); /* SGPIO10 */ SGPIO_GPIO_OUTREG &= ~(1L << 10); /* SGPIO10 */
} }
void sgpio_cpld_stream_disable() { void sgpio_cpld_stream_disable(sgpio_config_t* const config) {
(void)config;
// Disable codec data stream. // Disable codec data stream.
SGPIO_GPIO_OUTREG |= (1L << 10); /* SGPIO10 */ SGPIO_GPIO_OUTREG |= (1L << 10); /* SGPIO10 */
} }
bool sgpio_cpld_stream_is_enabled() { bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config) {
(void)config;
return (SGPIO_GPIO_OUTREG & (1L << 10)) == 0; /* SGPIO10 */ return (SGPIO_GPIO_OUTREG & (1L << 10)) == 0; /* SGPIO10 */
} }
bool sgpio_cpld_stream_rx_set_decimation(const uint_fast8_t n) { bool sgpio_cpld_stream_rx_set_decimation(sgpio_config_t* const config, const uint_fast8_t n) {
/* CPLD interface is three bits, SGPIO[15:13]: /* CPLD interface is three bits, SGPIO[15:13]:
* 111: decimate by 1 (skip_n=0, skip no samples) * 111: decimate by 1 (skip_n=0, skip no samples)
* 110: decimate by 2 (skip_n=1, skip every other sample) * 110: decimate by 2 (skip_n=1, skip every other sample)
@ -297,16 +257,13 @@ bool sgpio_cpld_stream_rx_set_decimation(const uint_fast8_t n) {
* 000: decimate by 8 (skip_n=7, skip seven of eight samples) * 000: decimate by 8 (skip_n=7, skip seven of eight samples)
*/ */
const uint_fast8_t skip_n = n - 1; const uint_fast8_t skip_n = n - 1;
GPIO_SET(GPIO5) = GPIOPIN14 | GPIOPIN13 | GPIOPIN12; gpio_write(config->gpio_rx_decimation[0], (skip_n & 1) == 0);
GPIO_CLR(GPIO5) = (skip_n & 7) << 12; gpio_write(config->gpio_rx_decimation[1], (skip_n & 2) == 0);
gpio_write(config->gpio_rx_decimation[2], (skip_n & 4) == 0);
return (skip_n < 8); return (skip_n < 8);
} }
void sgpio_cpld_stream_rx_set_q_invert(const uint_fast8_t invert) { void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, const uint_fast8_t invert) {
if( invert ) { gpio_write(config->gpio_rx_q_invert, invert);
GPIO_SET(GPIO0) = GPIOPIN13;
} else {
GPIO_CLR(GPIO0) = GPIOPIN13;
}
} }

View File

@ -22,26 +22,39 @@
#ifndef __SGPIO_H__ #ifndef __SGPIO_H__
#define __SGPIO_H__ #define __SGPIO_H__
#include <hackrf_core.h> #include <stdint.h>
#include <stdbool.h>
#include <libopencm3/lpc43xx/sgpio.h>
#include "gpio.h"
typedef enum { typedef enum {
SGPIO_DIRECTION_RX, SGPIO_DIRECTION_RX,
SGPIO_DIRECTION_TX, SGPIO_DIRECTION_TX,
} sgpio_direction_t; } sgpio_direction_t;
void sgpio_configure_pin_functions(); typedef struct sgpio_config_t {
void sgpio_test_interface(); gpio_t gpio_rx_q_invert;
gpio_t gpio_rx_decimation[3];
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( void sgpio_set_slice_mode(
sgpio_config_t* const config,
const bool multi_slice const bool multi_slice
); );
void sgpio_configure( void sgpio_configure(
sgpio_config_t* const config,
const sgpio_direction_t direction const sgpio_direction_t direction
); );
void sgpio_cpld_stream_enable(); void sgpio_cpld_stream_enable(sgpio_config_t* const config);
void sgpio_cpld_stream_disable(); void sgpio_cpld_stream_disable(sgpio_config_t* const config);
bool sgpio_cpld_stream_is_enabled(); bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config);
bool sgpio_cpld_stream_rx_set_decimation(const uint_fast8_t n); bool sgpio_cpld_stream_rx_set_decimation(sgpio_config_t* const config, const uint_fast8_t n);
void sgpio_cpld_stream_rx_set_q_invert(const uint_fast8_t invert); void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, const uint_fast8_t invert);
#endif//__SGPIO_H__ #endif//__SGPIO_H__

View File

@ -21,73 +21,50 @@
*/ */
#include "si5351c.h" #include "si5351c.h"
#include <libopencm3/lpc43xx/i2c.h>
enum pll_sources active_clock_source; enum pll_sources active_clock_source;
/* FIXME return i2c0 status from each function */
/* write to single register */ /* write to single register */
void si5351c_write_single(uint8_t reg, uint8_t val) void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val)
{ {
i2c0_tx_start(); const uint8_t data_tx[] = { reg, val };
i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE); si5351c_write(drv, data_tx, 2);
i2c0_tx_byte(reg);
i2c0_tx_byte(val);
i2c0_stop();
} }
/* read single register */ /* read single register */
uint8_t si5351c_read_single(uint8_t reg) uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg)
{ {
uint8_t val; const uint8_t data_tx[] = { reg };
uint8_t data_rx[] = { 0x00 };
/* set register address with write */ i2c_bus_transfer(drv->bus, drv->i2c_address, data_tx, 1, data_rx, 1);
i2c0_tx_start(); return data_rx[0];
i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE);
i2c0_tx_byte(reg);
/* read the value */
i2c0_tx_start();
i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_READ);
val = i2c0_rx_byte();
i2c0_stop();
return val;
} }
/* /*
* Write to one or more contiguous registers. data[0] should be the first * Write to one or more contiguous registers. data[0] should be the first
* register number, one or more values follow. * register number, one or more values follow.
*/ */
void si5351c_write(uint8_t* const data, const uint_fast8_t data_count) void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count)
{ {
uint_fast8_t i; i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0);
i2c0_tx_start();
i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE);
for (i = 0; i < data_count; i++)
i2c0_tx_byte(data[i]);
i2c0_stop();
} }
/* Disable all CLKx outputs. */ /* Disable all CLKx outputs. */
void si5351c_disable_all_outputs() void si5351c_disable_all_outputs(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 3, 0xFF }; uint8_t data[] = { 3, 0xFF };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* Turn off OEB pin control for all CLKx */ /* Turn off OEB pin control for all CLKx */
void si5351c_disable_oeb_pin_control() void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 9, 0xFF }; uint8_t data[] = { 9, 0xFF };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* Power down all CLKx */ /* Power down all CLKx */
void si5351c_power_down_all_clocks() void si5351c_power_down_all_clocks(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 16 uint8_t data[] = { 16
, SI5351C_CLK_POWERDOWN , SI5351C_CLK_POWERDOWN
@ -99,7 +76,7 @@ void si5351c_power_down_all_clocks()
, SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE , SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE
, SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE , SI5351C_CLK_POWERDOWN | SI5351C_CLK_INT_MODE
}; };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* /*
@ -107,20 +84,20 @@ void si5351c_power_down_all_clocks()
* Reads as 0xE4 on power-up * Reads as 0xE4 on power-up
* Set to 8pF based on crystal specs and HackRF One testing * Set to 8pF based on crystal specs and HackRF One testing
*/ */
void si5351c_set_crystal_configuration() void si5351c_set_crystal_configuration(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 183, 0x80 }; uint8_t data[] = { 183, 0x80 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* /*
* Register 187: Fanout Enable * Register 187: Fanout Enable
* Turn on XO and MultiSynth fanout only. * Turn on XO and MultiSynth fanout only.
*/ */
void si5351c_enable_xo_and_ms_fanout() void si5351c_enable_xo_and_ms_fanout(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 187, 0xD0 }; uint8_t data[] = { 187, 0xD0 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* /*
@ -129,34 +106,35 @@ void si5351c_enable_xo_and_ms_fanout()
* PLLA_SRC=0 (XTAL) * PLLA_SRC=0 (XTAL)
* PLLB_SRC=1 (CLKIN) * PLLB_SRC=1 (CLKIN)
*/ */
void si5351c_configure_pll_sources(void) void si5351c_configure_pll_sources(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 15, 0x08 }; uint8_t data[] = { 15, 0x08 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
/* MultiSynth NA (PLLA) and NB (PLLB) */ /* MultiSynth NA (PLLA) and NB (PLLB) */
void si5351c_configure_pll_multisynth(void) void si5351c_configure_pll_multisynth(si5351c_driver_t* const drv)
{ {
//init plla to (0x0e00+512)/128*25mhz xtal = 800mhz -> int mode //init plla to (0x0e00+512)/128*25mhz xtal = 800mhz -> int mode
uint8_t data[] = { 26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00 }; uint8_t data[] = { 26, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
/* 10 MHz input on CLKIN for PLLB */ /* 10 MHz input on CLKIN for PLLB */
data[0] = 34; data[0] = 34;
data[4] = 0x26; data[4] = 0x26;
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
void si5351c_reset_pll(void) void si5351c_reset_pll(si5351c_driver_t* const drv)
{ {
/* reset PLLA and PLLB */ /* reset PLLA and PLLB */
uint8_t data[] = { 177, 0xA0 }; uint8_t data[] = { 177, 0xA0 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
void si5351c_configure_multisynth(const uint_fast8_t ms_number, 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 uint32_t p1, const uint32_t p2, const uint32_t p3,
const uint_fast8_t r_div) const uint_fast8_t r_div)
{ {
@ -183,7 +161,7 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number,
(((p3 >> 16) & 0xF) << 4) | (((p2 >> 16) & 0xF) << 0), (((p3 >> 16) & 0xF) << 4) | (((p2 >> 16) & 0xF) << 0),
(p2 >> 8) & 0xFF, (p2 >> 8) & 0xFF,
(p2 >> 0) & 0xFF }; (p2 >> 0) & 0xFF };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
#ifdef JELLYBEAN #ifdef JELLYBEAN
@ -232,15 +210,15 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number,
* CLK5_SRC=3 (MS5 as input source) * CLK5_SRC=3 (MS5 as input source)
* CLK5_IDRV=3 (8mA) * CLK5_IDRV=3 (8mA)
*/ */
void si5351c_configure_clock_control() void si5351c_configure_clock_control(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 16, 0x4F, 0x4B, 0x4B, 0x4B, 0x0F, 0x4F, 0xC0, 0xC0 }; uint8_t data[] = { 16, 0x4F, 0x4B, 0x4B, 0x4B, 0x0F, 0x4F, 0xC0, 0xC0 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
#endif #endif
#if (defined JAWBREAKER || defined HACKRF_ONE) #if (defined JAWBREAKER || defined HACKRF_ONE)
void si5351c_configure_clock_control(const enum pll_sources source) void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll_sources source)
{ {
uint8_t pll; uint8_t pll;
@ -261,54 +239,54 @@ void si5351c_configure_clock_control(const enum pll_sources source)
,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_CLK_INT_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_SELF) | SI5351C_CLK_IDRV(SI5351C_CLK_IDRV_8MA)
}; };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
#endif #endif
/* Enable CLK outputs 0, 1, 2, 3, 4, 5, 7 only. */ /* Enable CLK outputs 0, 1, 2, 3, 4, 5, 7 only. */
void si5351c_enable_clock_outputs() void si5351c_enable_clock_outputs(si5351c_driver_t* const drv)
{ {
uint8_t data[] = { 3, 0x40 }; uint8_t data[] = { 3, 0x40 };
si5351c_write(data, sizeof(data)); si5351c_write(drv, data, sizeof(data));
} }
void si5351c_set_int_mode(const uint_fast8_t ms_number, const uint_fast8_t on){ 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}; uint8_t data[] = {16, 0};
if(ms_number < 8){ if(ms_number < 8){
data[0] = 16 + ms_number; data[0] = 16 + ms_number;
data[1] = si5351c_read_single(data[0]); data[1] = si5351c_read_single(drv, data[0]);
if(on) if(on)
data[1] |= SI5351C_CLK_INT_MODE; data[1] |= SI5351C_CLK_INT_MODE;
else else
data[1] &= ~(SI5351C_CLK_INT_MODE); data[1] &= ~(SI5351C_CLK_INT_MODE);
si5351c_write(data, 2); si5351c_write(drv, data, 2);
} }
} }
void si5351c_set_clock_source(const enum pll_sources source) void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source)
{ {
si5351c_configure_clock_control(source); si5351c_configure_clock_control(drv, source);
active_clock_source = source; active_clock_source = source;
} }
void si5351c_activate_best_clock_source(void) void si5351c_activate_best_clock_source(si5351c_driver_t* const drv)
{ {
uint8_t device_status = si5351c_read_single(0); uint8_t device_status = si5351c_read_single(drv, 0);
if (device_status & SI5351C_LOS) { if (device_status & SI5351C_LOS) {
/* CLKIN not detected */ /* CLKIN not detected */
if (active_clock_source == PLL_SOURCE_CLKIN) { if (active_clock_source == PLL_SOURCE_CLKIN) {
si5351c_set_clock_source(PLL_SOURCE_XTAL); si5351c_set_clock_source(drv, PLL_SOURCE_XTAL);
} }
} else { } else {
/* CLKIN detected */ /* CLKIN detected */
if (active_clock_source == PLL_SOURCE_XTAL) { if (active_clock_source == PLL_SOURCE_XTAL) {
si5351c_set_clock_source(PLL_SOURCE_CLKIN); si5351c_set_clock_source(drv, PLL_SOURCE_CLKIN);
} }
} }
} }

View File

@ -30,8 +30,9 @@ extern "C"
#include <stdint.h> #include <stdint.h>
#include "i2c_bus.h"
#define SI_INTDIV(x) (x*128-512) #define SI_INTDIV(x) (x*128-512)
#define SI5351C_I2C_ADDR (0x60 << 1)
#define SI5351C_CLK_POWERDOWN (1<<7) #define SI5351C_CLK_POWERDOWN (1<<7)
#define SI5351C_CLK_INT_MODE (1<<6) #define SI5351C_CLK_INT_MODE (1<<6)
@ -62,26 +63,32 @@ enum pll_sources {
PLL_SOURCE_CLKIN = 1, PLL_SOURCE_CLKIN = 1,
}; };
void si5351c_disable_all_outputs(); typedef struct {
void si5351c_disable_oeb_pin_control(); i2c_bus_t* const bus;
void si5351c_power_down_all_clocks(); uint8_t i2c_address;
void si5351c_set_crystal_configuration(); } si5351c_driver_t;
void si5351c_enable_xo_and_ms_fanout();
void si5351c_configure_pll_sources(void); void si5351c_disable_all_outputs(si5351c_driver_t* const drv);
void si5351c_configure_pll_multisynth(void); void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv);
void si5351c_reset_pll(void); void si5351c_power_down_all_clocks(si5351c_driver_t* const drv);
void si5351c_configure_multisynth(const uint_fast8_t ms_number, 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 uint32_t p1, const uint32_t p2, const uint32_t p3,
const uint_fast8_t r_div); const uint_fast8_t r_div);
void si5351c_configure_clock_control(const enum pll_sources source); void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll_sources source);
void si5351c_enable_clock_outputs(); void si5351c_enable_clock_outputs(si5351c_driver_t* const drv);
void si5351c_set_int_mode(const uint_fast8_t ms_number, const uint_fast8_t on); 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);
void si5351c_activate_best_clock_source(si5351c_driver_t* const drv);
void si5351c_write_single(uint8_t reg, uint8_t val); void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val);
uint8_t si5351c_read_single(uint8_t reg); uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg);
void si5351c_write(uint8_t* const data, const uint_fast8_t data_count); void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count);
void si5351c_set_clock_source(const enum pll_sources source);
void si5351c_activate_best_clock_source(void);
#ifdef __cplusplus #ifdef __cplusplus
} }

38
firmware/common/spi_bus.c Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "spi_bus.h"
void spi_bus_start(spi_bus_t* const bus, const void* const config) {
bus->start(bus, config);
}
void spi_bus_stop(spi_bus_t* const bus) {
bus->stop(bus);
}
void spi_bus_transfer(spi_bus_t* const bus, void* const data, const size_t count) {
bus->transfer(bus, data, count);
}
void spi_bus_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count) {
bus->transfer_gather(bus, transfers, count);
}

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

@ -0,0 +1,49 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPI_BUS_H__
#define __SPI_BUS_H__
#include <stddef.h>
typedef struct {
void* const data;
const size_t count;
} spi_transfer_t;
struct spi_bus_t;
typedef struct spi_bus_t spi_bus_t;
struct spi_bus_t {
void* const obj;
const void* config;
void (*start)(spi_bus_t* const bus, const void* const config);
void (*stop)(spi_bus_t* const bus);
void (*transfer)(spi_bus_t* const bus, void* const data, const size_t count);
void (*transfer_gather)(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count);
};
void spi_bus_start(spi_bus_t* const bus, const void* const config);
void spi_bus_stop(spi_bus_t* const bus);
void spi_bus_transfer(spi_bus_t* const bus, void* const data, const size_t count);
void spi_bus_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count);
#endif/*__SPI_BUS_H__*/

109
firmware/common/spi_ssp.c Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "spi_ssp.h"
#include <libopencm3/lpc43xx/rgu.h>
#include <libopencm3/lpc43xx/ssp.h>
void spi_ssp_start(spi_bus_t* const bus, const void* const _config) {
const ssp_config_t* const config = _config;
if( bus->obj == (void*)SSP0_BASE ) {
/* Reset SPIFI peripheral before to Erase/Write SPIFI memory through SPI */
RESET_CTRL1 = RESET_CTRL1_SPIFI_RST;
}
gpio_set(config->gpio_select);
gpio_output(config->gpio_select);
SSP_CR1(bus->obj) = 0;
SSP_CPSR(bus->obj) = config->clock_prescale_rate;
SSP_CR0(bus->obj) =
(config->serial_clock_rate << 8)
| SSP_CPOL_0_CPHA_0
| SSP_FRAME_SPI
| config->data_bits
;
SSP_CR1(bus->obj) =
SSP_SLAVE_OUT_ENABLE
| SSP_MASTER
| SSP_ENABLE
| SSP_MODE_NORMAL
;
bus->config = config;
}
void spi_ssp_stop(spi_bus_t* const bus) {
SSP_CR1(bus->obj) = 0;
}
static void spi_ssp_wait_for_tx_fifo_not_full(spi_bus_t* const bus) {
while( (SSP_SR(bus->obj) & SSP_SR_TNF) == 0 );
}
static void spi_ssp_wait_for_rx_fifo_not_empty(spi_bus_t* const bus) {
while( (SSP_SR(bus->obj) & SSP_SR_RNE) == 0 );
}
static void spi_ssp_wait_for_not_busy(spi_bus_t* const bus) {
while( SSP_SR(bus->obj) & SSP_SR_BSY );
}
static uint32_t spi_ssp_transfer_word(spi_bus_t* const bus, const uint32_t data) {
spi_ssp_wait_for_tx_fifo_not_full(bus);
SSP_DR(bus->obj) = data;
spi_ssp_wait_for_not_busy(bus);
spi_ssp_wait_for_rx_fifo_not_empty(bus);
return SSP_DR(bus->obj);
}
void spi_ssp_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count) {
const ssp_config_t* const config = bus->config;
const bool word_size_u16 = (SSP_CR0(bus->obj) & 0xf) > SSP_DATA_8BITS;
gpio_clear(config->gpio_select);
for(size_t i=0; i<count; i++) {
const size_t data_count = transfers[i].count;
if( word_size_u16 ) {
uint16_t* const data = transfers[i].data;
for(size_t j=0; j<data_count; j++) {
data[j] = spi_ssp_transfer_word(bus, data[j]);
}
} else {
uint8_t* const data = transfers[i].data;
for(size_t j=0; j<data_count; j++) {
data[j] = spi_ssp_transfer_word(bus, data[j]);
}
}
}
gpio_set(config->gpio_select);
}
void spi_ssp_transfer(spi_bus_t* const bus, void* const data, const size_t count) {
const spi_transfer_t transfers[] = {
{ data, count },
};
spi_ssp_transfer_gather(bus, transfers, 1);
}

46
firmware/common/spi_ssp.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPI_SSP_H__
#define __SPI_SSP_H__
#include <stdint.h>
#include <stddef.h>
#include "spi_bus.h"
#include "gpio.h"
#include <libopencm3/lpc43xx/ssp.h>
typedef struct ssp_config_t {
ssp_datasize_t data_bits;
uint8_t serial_clock_rate;
uint8_t clock_prescale_rate;
gpio_t gpio_select;
} ssp_config_t;
void spi_ssp_start(spi_bus_t* const bus, const void* const config);
void spi_ssp_stop(spi_bus_t* const bus);
void spi_ssp_transfer(spi_bus_t* const bus, void* const data, const size_t count);
void spi_ssp_transfer_gather(spi_bus_t* const bus, const spi_transfer_t* const transfers, const size_t count);
#endif/*__SPI_SSP_H__*/

View File

@ -25,18 +25,16 @@
#include <libopencm3/lpc43xx/m4/nvic.h> #include <libopencm3/lpc43xx/m4/nvic.h>
#include <libopencm3/lpc43xx/sgpio.h> #include <libopencm3/lpc43xx/sgpio.h>
#include <sgpio.h> void baseband_streaming_enable(sgpio_config_t* const sgpio_config) {
void baseband_streaming_enable() {
nvic_set_priority(NVIC_SGPIO_IRQ, 0); nvic_set_priority(NVIC_SGPIO_IRQ, 0);
nvic_enable_irq(NVIC_SGPIO_IRQ); nvic_enable_irq(NVIC_SGPIO_IRQ);
SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A); SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A);
sgpio_cpld_stream_enable(); sgpio_cpld_stream_enable(sgpio_config);
} }
void baseband_streaming_disable() { void baseband_streaming_disable(sgpio_config_t* const sgpio_config) {
sgpio_cpld_stream_disable(); sgpio_cpld_stream_disable(sgpio_config);
nvic_disable_irq(NVIC_SGPIO_IRQ); nvic_disable_irq(NVIC_SGPIO_IRQ);
} }

View File

@ -23,7 +23,9 @@
#ifndef __STREAMING_H__ #ifndef __STREAMING_H__
#define __STREAMING_H__ #define __STREAMING_H__
void baseband_streaming_enable(); #include <sgpio.h>
void baseband_streaming_disable();
void baseband_streaming_enable(sgpio_config_t* const sgpio_config);
void baseband_streaming_disable(sgpio_config_t* const sgpio_config);
#endif/*__STREAMING_H__*/ #endif/*__STREAMING_H__*/

View File

@ -22,6 +22,7 @@
#include "tuning.h" #include "tuning.h"
#include <hackrf_core.h>
#include <rffc5071.h> #include <rffc5071.h>
#include <max2837.h> #include <max2837.h>
#include <sgpio.h> #include <sgpio.h>
@ -62,25 +63,25 @@ bool set_freq(const uint64_t freq)
success = true; success = true;
const max2837_mode_t prior_max2837_mode = max2837_mode(); const max2837_mode_t prior_max2837_mode = max2837_mode(&max2837);
max2837_mode_standby(); max2837_set_mode(&max2837, MAX2837_MODE_STANDBY);
if(freq_mhz < MAX_LP_FREQ_MHZ) if(freq_mhz < MAX_LP_FREQ_MHZ)
{ {
rf_path_set_filter(RF_PATH_FILTER_LOW_PASS); rf_path_set_filter(&rf_path, RF_PATH_FILTER_LOW_PASS);
/* IF is graduated from 2650 MHz to 2343 MHz */ /* IF is graduated from 2650 MHz to 2343 MHz */
max2837_freq_nominal_hz = 2650000000 - (freq / 7); max2837_freq_nominal_hz = 2650000000 - (freq / 7);
RFFC5071_freq_mhz = (max2837_freq_nominal_hz / FREQ_ONE_MHZ) + freq_mhz; RFFC5071_freq_mhz = (max2837_freq_nominal_hz / FREQ_ONE_MHZ) + freq_mhz;
/* Set Freq and read real freq */ /* Set Freq and read real freq */
real_RFFC5071_freq_hz = rffc5071_set_frequency(RFFC5071_freq_mhz); real_RFFC5071_freq_hz = rffc5071_set_frequency(&rffc5072, RFFC5071_freq_mhz);
max2837_set_frequency(real_RFFC5071_freq_hz - freq); max2837_set_frequency(&max2837, real_RFFC5071_freq_hz - freq);
sgpio_cpld_stream_rx_set_q_invert(1); sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1);
}else if( (freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ) ) }else if( (freq_mhz >= MIN_BYPASS_FREQ_MHZ) && (freq_mhz < MAX_BYPASS_FREQ_MHZ) )
{ {
rf_path_set_filter(RF_PATH_FILTER_BYPASS); rf_path_set_filter(&rf_path, RF_PATH_FILTER_BYPASS);
MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz; MAX2837_freq_hz = (freq_mhz * FREQ_ONE_MHZ) + freq_hz;
/* RFFC5071_freq_mhz <= not used in Bypass mode */ /* RFFC5071_freq_mhz <= not used in Bypass mode */
max2837_set_frequency(MAX2837_freq_hz); max2837_set_frequency(&max2837, MAX2837_freq_hz);
sgpio_cpld_stream_rx_set_q_invert(0); sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0);
}else if( (freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ) ) }else if( (freq_mhz >= MIN_HP_FREQ_MHZ) && (freq_mhz <= MAX_HP_FREQ_MHZ) )
{ {
if (freq_mhz < MID1_HP_FREQ_MHZ) { if (freq_mhz < MID1_HP_FREQ_MHZ) {
@ -93,18 +94,18 @@ bool set_freq(const uint64_t freq)
/* IF is graduated from 2500 MHz to 2738 MHz */ /* IF is graduated from 2500 MHz to 2738 MHz */
max2837_freq_nominal_hz = 2500000000 + ((freq - 5100000000) / 9); max2837_freq_nominal_hz = 2500000000 + ((freq - 5100000000) / 9);
} }
rf_path_set_filter(RF_PATH_FILTER_HIGH_PASS); rf_path_set_filter(&rf_path, RF_PATH_FILTER_HIGH_PASS);
RFFC5071_freq_mhz = freq_mhz - (max2837_freq_nominal_hz / FREQ_ONE_MHZ); RFFC5071_freq_mhz = freq_mhz - (max2837_freq_nominal_hz / FREQ_ONE_MHZ);
/* Set Freq and read real freq */ /* Set Freq and read real freq */
real_RFFC5071_freq_hz = rffc5071_set_frequency(RFFC5071_freq_mhz); real_RFFC5071_freq_hz = rffc5071_set_frequency(&rffc5072, RFFC5071_freq_mhz);
max2837_set_frequency(freq - real_RFFC5071_freq_hz); max2837_set_frequency(&max2837, freq - real_RFFC5071_freq_hz);
sgpio_cpld_stream_rx_set_q_invert(0); sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0);
}else }else
{ {
/* Error freq_mhz too high */ /* Error freq_mhz too high */
success = false; success = false;
} }
max2837_set_mode(prior_max2837_mode); max2837_set_mode(&max2837, prior_max2837_mode);
if( success ) { if( success ) {
freq_cache = freq; freq_cache = freq;
} }
@ -128,15 +129,15 @@ bool set_freq_explicit(const uint64_t if_freq_hz, const uint64_t lo_freq_hz,
return false; return false;
} }
rf_path_set_filter(path); rf_path_set_filter(&rf_path, path);
max2837_set_frequency(if_freq_hz); max2837_set_frequency(&max2837, if_freq_hz);
if (lo_freq_hz > if_freq_hz) { if (lo_freq_hz > if_freq_hz) {
sgpio_cpld_stream_rx_set_q_invert(1); sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 1);
} else { } else {
sgpio_cpld_stream_rx_set_q_invert(0); sgpio_cpld_stream_rx_set_q_invert(&sgpio_config, 0);
} }
if (path != RF_PATH_FILTER_BYPASS) { if (path != RF_PATH_FILTER_BYPASS) {
(void)rffc5071_set_frequency(lo_freq_hz / FREQ_ONE_MHZ); (void)rffc5071_set_frequency(&rffc5072, lo_freq_hz / FREQ_ONE_MHZ);
} }
return true; return true;
} }

View File

@ -1,6 +1,7 @@
/* /*
* Copyright 2013 Michael Ossmann * Copyright 2013 Michael Ossmann
* Copyright 2013 Benjamin Vernoux * Copyright 2013 Benjamin Vernoux
* Copyright 2014 Jared Boone, ShareBrained Technology
* *
* This file is part of HackRF. * This file is part of HackRF.
* *
@ -27,183 +28,139 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#include "w25q80bv.h" #include "w25q80bv.h"
#include "hackrf_core.h"
#include <libopencm3/lpc43xx/ssp.h> #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/gpio.h> #define W25Q80BV_READ_DATA 0x03
#include <libopencm3/lpc43xx/rgu.h> #define W25Q80BV_FAST_READ 0x0b
#define W25Q80BV_WRITE_ENABLE 0x06
#define W25Q80BV_CHIP_ERASE 0xC7
#define W25Q80BV_READ_STATUS1 0x05
#define W25Q80BV_PAGE_PROGRAM 0x02
#define W25Q80BV_DEVICE_ID 0xAB
#define W25Q80BV_UNIQUE_ID 0x4B
#define W25Q80BV_STATUS_BUSY 0x01
#define W25Q80BV_DEVICE_ID_RES 0x13 /* Expected device_id for W25Q80BV */
/* /*
* Set up pins for GPIO and SPI control, configure SSP0 peripheral for SPI. * Set up pins for GPIO and SPI control, configure SSP0 peripheral for SPI.
* SSP0_SSEL is controlled by GPIO in order to handle various transfer lengths. * SSP0_SSEL is controlled by GPIO in order to handle various transfer lengths.
*/ */
void w25q80bv_setup(w25q80bv_driver_t* const drv)
void w25q80bv_setup(void)
{ {
uint8_t device_id; uint8_t device_id;
const uint8_t serial_clock_rate = 2;
const uint8_t clock_prescale_rate = 2;
/* Reset SPIFI peripheral before to Erase/Write SPIFI memory through SPI */ drv->page_len = 256U;
RESET_CTRL1 = RESET_CTRL1_SPIFI_RST; drv->num_pages = 4096U;
drv->num_bytes = 1048576U;
/* Init SPIFI GPIO to Normal GPIO */ drv->target_init(drv);
scu_pinmux(P3_3, (SCU_SSP_IO | SCU_CONF_FUNCTION2)); // P3_3 SPIFI_SCK => SSP0_SCK
scu_pinmux(P3_4, (SCU_GPIO_FAST | SCU_CONF_FUNCTION0)); // P3_4 SPIFI SPIFI_SIO3 IO3 => GPIO1[14]
scu_pinmux(P3_5, (SCU_GPIO_FAST | SCU_CONF_FUNCTION0)); // P3_5 SPIFI SPIFI_SIO2 IO2 => GPIO1[15]
scu_pinmux(P3_6, (SCU_GPIO_FAST | SCU_CONF_FUNCTION0)); // P3_6 SPIFI SPIFI_MISO IO1 => GPIO0[6]
scu_pinmux(P3_7, (SCU_GPIO_FAST | SCU_CONF_FUNCTION4)); // P3_7 SPIFI SPIFI_MOSI IO0 => GPIO5[10]
scu_pinmux(P3_8, (SCU_GPIO_FAST | SCU_CONF_FUNCTION4)); // P3_8 SPIFI SPIFI_CS => GPIO5[11]
/* configure SSP pins */
scu_pinmux(SCU_SSP0_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP0_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP0_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION2));
/* configure GPIO pins */
scu_pinmux(SCU_FLASH_HOLD, SCU_GPIO_FAST);
scu_pinmux(SCU_FLASH_WP, SCU_GPIO_FAST);
scu_pinmux(SCU_SSP0_SSEL, (SCU_GPIO_FAST | SCU_CONF_FUNCTION4));
/* drive SSEL, HOLD, and WP pins high */
gpio_set(PORT_FLASH, (PIN_FLASH_HOLD | PIN_FLASH_WP));
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
/* Set GPIO pins as outputs. */
GPIO1_DIR |= (PIN_FLASH_HOLD | PIN_FLASH_WP);
GPIO5_DIR |= PIN_SSP0_SSEL;
/* initialize SSP0 */
ssp_init(SSP0_NUM,
SSP_DATA_8BITS,
SSP_FRAME_SPI,
SSP_CPOL_0_CPHA_0,
serial_clock_rate,
clock_prescale_rate,
SSP_MODE_NORMAL,
SSP_MASTER,
SSP_SLAVE_OUT_ENABLE);
device_id = 0; device_id = 0;
while(device_id != W25Q80BV_DEVICE_ID_RES) while(device_id != W25Q80BV_DEVICE_ID_RES)
{ {
device_id = w25q80bv_get_device_id(); device_id = w25q80bv_get_device_id(drv);
} }
} }
uint8_t w25q80bv_get_status(void) uint8_t w25q80bv_get_status(w25q80bv_driver_t* const drv)
{ {
uint8_t value; uint8_t data[] = { W25Q80BV_READ_STATUS1, 0xFF };
spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL); return data[1];
ssp_transfer(SSP0_NUM, W25Q80BV_READ_STATUS1);
value = ssp_transfer(SSP0_NUM, 0xFF);
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
return value;
} }
/* Release power down / Device ID */ /* Release power down / Device ID */
uint8_t w25q80bv_get_device_id(void) uint8_t w25q80bv_get_device_id(w25q80bv_driver_t* const drv)
{ {
uint8_t value; uint8_t data[] = {
W25Q80BV_DEVICE_ID,
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL); 0xFF, 0xFF, 0xFF, 0xFF
ssp_transfer(SSP0_NUM, W25Q80BV_DEVICE_ID); };
spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
/* Read 3 dummy bytes */ return data[4];
value = ssp_transfer(SSP0_NUM, 0xFF);
value = ssp_transfer(SSP0_NUM, 0xFF);
value = ssp_transfer(SSP0_NUM, 0xFF);
/* Read Device ID shall return 0x13 for W25Q80BV */
value = ssp_transfer(SSP0_NUM, 0xFF);
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
return value;
} }
void w25q80bv_get_unique_id(w25q80bv_unique_id_t* unique_id) void w25q80bv_get_unique_id(w25q80bv_driver_t* const drv, w25q80bv_unique_id_t* unique_id)
{ {
int i; uint8_t data[] = {
uint8_t value; W25Q80BV_UNIQUE_ID,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL); for(size_t i=0; i<8; i++) {
ssp_transfer(SSP0_NUM, W25Q80BV_UNIQUE_ID); unique_id->id_8b[i] = data[5+i];
}
/* Read 4 dummy bytes */
for(i=0; i<4; i++)
value = ssp_transfer(SSP0_NUM, 0xFF);
/* Read Unique ID 64bits (8*8) */
for(i=0; i<8; i++)
{
value = ssp_transfer(SSP0_NUM, 0xFF);
unique_id->id_8b[i] = value;
} }
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL); void w25q80bv_wait_while_busy(w25q80bv_driver_t* const drv)
}
void w25q80bv_wait_while_busy(void)
{ {
while (w25q80bv_get_status() & W25Q80BV_STATUS_BUSY); while (w25q80bv_get_status(drv) & W25Q80BV_STATUS_BUSY);
} }
void w25q80bv_write_enable(void) void w25q80bv_write_enable(w25q80bv_driver_t* const drv)
{ {
w25q80bv_wait_while_busy(); w25q80bv_wait_while_busy(drv);
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
ssp_transfer(SSP0_NUM, W25Q80BV_WRITE_ENABLE); uint8_t data[] = { W25Q80BV_WRITE_ENABLE };
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL); spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
} }
void w25q80bv_chip_erase(void) void w25q80bv_chip_erase(w25q80bv_driver_t* const drv)
{ {
uint8_t device_id; uint8_t device_id;
device_id = 0; device_id = 0;
while(device_id != W25Q80BV_DEVICE_ID_RES) while(device_id != W25Q80BV_DEVICE_ID_RES)
{ {
device_id = w25q80bv_get_device_id(); device_id = w25q80bv_get_device_id(drv);
} }
w25q80bv_write_enable(); w25q80bv_write_enable(drv);
w25q80bv_wait_while_busy(); w25q80bv_wait_while_busy(drv);
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
ssp_transfer(SSP0_NUM, W25Q80BV_CHIP_ERASE); uint8_t data[] = { W25Q80BV_CHIP_ERASE };
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL); spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
} }
/* write up a 256 byte page or partial page */ /* write up a 256 byte page or partial page */
void w25q80bv_page_program(const uint32_t addr, const uint16_t len, const uint8_t* data) static void w25q80bv_page_program(w25q80bv_driver_t* const drv, const uint32_t addr, const uint16_t len, uint8_t* data)
{ {
int i;
/* do nothing if asked to write beyond a page boundary */ /* do nothing if asked to write beyond a page boundary */
if (((addr & 0xFF) + len) > W25Q80BV_PAGE_LEN) if (((addr & 0xFF) + len) > drv->page_len)
return; return;
/* do nothing if we would overflow the flash */ /* do nothing if we would overflow the flash */
if (addr > (W25Q80BV_NUM_BYTES - len)) if (addr > (drv->num_bytes - len))
return; return;
w25q80bv_write_enable(); w25q80bv_write_enable(drv);
w25q80bv_wait_while_busy(); w25q80bv_wait_while_busy(drv);
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL); uint8_t header[] = {
ssp_transfer(SSP0_NUM, W25Q80BV_PAGE_PROGRAM); W25Q80BV_PAGE_PROGRAM,
ssp_transfer(SSP0_NUM, (addr & 0xFF0000) >> 16); (addr & 0xFF0000) >> 16,
ssp_transfer(SSP0_NUM, (addr & 0xFF00) >> 8); (addr & 0xFF00) >> 8,
ssp_transfer(SSP0_NUM, addr & 0xFF); addr & 0xFF
for (i = 0; i < len; i++) };
ssp_transfer(SSP0_NUM, data[i]);
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL); const spi_transfer_t transfers[] = {
{ header, ARRAY_SIZE(header) },
{ data, len }
};
spi_bus_transfer_gather(drv->bus, transfers, ARRAY_SIZE(transfers));
} }
/* write an arbitrary number of bytes */ /* write an arbitrary number of bytes */
void w25q80bv_program(uint32_t addr, uint32_t len, const uint8_t* data) void w25q80bv_program(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, uint8_t* data)
{ {
uint16_t first_block_len; uint16_t first_block_len;
uint8_t device_id; uint8_t device_id;
@ -211,36 +168,36 @@ void w25q80bv_program(uint32_t addr, uint32_t len, const uint8_t* data)
device_id = 0; device_id = 0;
while(device_id != W25Q80BV_DEVICE_ID_RES) while(device_id != W25Q80BV_DEVICE_ID_RES)
{ {
device_id = w25q80bv_get_device_id(); device_id = w25q80bv_get_device_id(drv);
} }
/* do nothing if we would overflow the flash */ /* do nothing if we would overflow the flash */
if ((len > W25Q80BV_NUM_BYTES) || (addr > W25Q80BV_NUM_BYTES) if ((len > drv->num_bytes) || (addr > drv->num_bytes)
|| ((addr + len) > W25Q80BV_NUM_BYTES)) || ((addr + len) > drv->num_bytes))
return; return;
/* handle start not at page boundary */ /* handle start not at page boundary */
first_block_len = W25Q80BV_PAGE_LEN - (addr % W25Q80BV_PAGE_LEN); first_block_len = drv->page_len - (addr % drv->page_len);
if (len < first_block_len) if (len < first_block_len)
first_block_len = len; first_block_len = len;
if (first_block_len) { if (first_block_len) {
w25q80bv_page_program(addr, first_block_len, data); w25q80bv_page_program(drv, addr, first_block_len, data);
addr += first_block_len; addr += first_block_len;
data += first_block_len; data += first_block_len;
len -= first_block_len; len -= first_block_len;
} }
/* one page at a time on boundaries */ /* one page at a time on boundaries */
while (len >= W25Q80BV_PAGE_LEN) { while (len >= drv->page_len) {
w25q80bv_page_program(addr, W25Q80BV_PAGE_LEN, data); w25q80bv_page_program(drv, addr, drv->page_len, data);
addr += W25Q80BV_PAGE_LEN; addr += drv->page_len;
data += W25Q80BV_PAGE_LEN; data += drv->page_len;
len -= W25Q80BV_PAGE_LEN; len -= drv->page_len;
} }
/* handle end not at page boundary */ /* handle end not at page boundary */
if (len) { if (len) {
w25q80bv_page_program(addr, len, data); w25q80bv_page_program(drv, addr, len, data);
} }
} }

View File

@ -1,6 +1,7 @@
/* /*
* Copyright 2013 Michael Ossmann * Copyright 2013 Michael Ossmann
* Copyright 2013 Benjamin Vernoux * Copyright 2013 Benjamin Vernoux
* Copyright 2014 Jared Boone, ShareBrained Technology
* *
* This file is part of HackRF. * This file is part of HackRF.
* *
@ -23,23 +24,11 @@
#ifndef __W25Q80BV_H__ #ifndef __W25Q80BV_H__
#define __W25Q80BV_H__ #define __W25Q80BV_H__
#define W25Q80BV_PAGE_LEN 256U #include <stdint.h>
#define W25Q80BV_NUM_PAGES 4096U #include <stddef.h>
#define W25Q80BV_NUM_BYTES 1048576U
#define W25Q80BV_READ_DATA 0x03 #include "spi_bus.h"
#define W25Q80BV_FAST_READ 0x0b #include "gpio.h"
#define W25Q80BV_WRITE_ENABLE 0x06
#define W25Q80BV_CHIP_ERASE 0xC7
#define W25Q80BV_READ_STATUS1 0x05
#define W25Q80BV_PAGE_PROGRAM 0x02
#define W25Q80BV_DEVICE_ID 0xAB
#define W25Q80BV_UNIQUE_ID 0x4B
#define W25Q80BV_STATUS_BUSY 0x01
#define W25Q80BV_DEVICE_ID_RES 0x13 /* Expected device_id for W25Q80BV */
typedef union typedef union
{ {
@ -48,11 +37,24 @@ typedef union
uint8_t id_8b[8]; /* 8*8bits 64bits Unique ID */ uint8_t id_8b[8]; /* 8*8bits 64bits Unique ID */
} w25q80bv_unique_id_t; } w25q80bv_unique_id_t;
void w25q80bv_setup(void); struct w25q80bv_driver_t;
void w25q80bv_chip_erase(void); typedef struct w25q80bv_driver_t w25q80bv_driver_t;
void w25q80bv_program(uint32_t addr, uint32_t len, const uint8_t* data);
uint8_t w25q80bv_get_device_id(void); struct w25q80bv_driver_t {
void w25q80bv_get_unique_id(w25q80bv_unique_id_t* unique_id); spi_bus_t* bus;
gpio_t gpio_hold;
gpio_t gpio_wp;
void (*target_init)(w25q80bv_driver_t* const drv);
size_t page_len;
size_t num_pages;
size_t num_bytes;
};
void w25q80bv_setup(w25q80bv_driver_t* const drv);
void w25q80bv_chip_erase(w25q80bv_driver_t* const drv);
void w25q80bv_program(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, uint8_t* data);
uint8_t w25q80bv_get_device_id(w25q80bv_driver_t* const drv);
void w25q80bv_get_unique_id(w25q80bv_driver_t* const drv, w25q80bv_unique_id_t* unique_id);
void w25q80bv_read(uint32_t addr, uint32_t len, uint8_t* const data); void w25q80bv_read(uint32_t addr, uint32_t len, uint8_t* const data);
#endif//__W25Q80BV_H__ #endif//__W25Q80BV_H__

View File

@ -0,0 +1,59 @@
/*
* 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 "w25q80bv_target.h"
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h"
/* TODO: Why is SSEL being controlled manually when SSP0 could do it
* automatically?
*/
void w25q80bv_target_init(w25q80bv_driver_t* const drv) {
(void)drv;
/* Init SPIFI GPIO to Normal GPIO */
scu_pinmux(P3_3, (SCU_SSP_IO | SCU_CONF_FUNCTION2)); // P3_3 SPIFI_SCK => SSP0_SCK
scu_pinmux(P3_4, (SCU_GPIO_FAST | SCU_CONF_FUNCTION0)); // P3_4 SPIFI SPIFI_SIO3 IO3 => GPIO1[14]
scu_pinmux(P3_5, (SCU_GPIO_FAST | SCU_CONF_FUNCTION0)); // P3_5 SPIFI SPIFI_SIO2 IO2 => GPIO1[15]
scu_pinmux(P3_6, (SCU_GPIO_FAST | SCU_CONF_FUNCTION0)); // P3_6 SPIFI SPIFI_MISO IO1 => GPIO0[6]
scu_pinmux(P3_7, (SCU_GPIO_FAST | SCU_CONF_FUNCTION4)); // P3_7 SPIFI SPIFI_MOSI IO0 => GPIO5[10]
scu_pinmux(P3_8, (SCU_GPIO_FAST | SCU_CONF_FUNCTION4)); // P3_8 SPIFI SPIFI_CS => GPIO5[11]
/* configure SSP pins */
scu_pinmux(SCU_SSP0_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP0_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
scu_pinmux(SCU_SSP0_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION2));
/* configure GPIO pins */
scu_pinmux(SCU_FLASH_HOLD, SCU_GPIO_FAST);
scu_pinmux(SCU_FLASH_WP, SCU_GPIO_FAST);
scu_pinmux(SCU_SSP0_SSEL, (SCU_GPIO_FAST | SCU_CONF_FUNCTION4));
/* drive SSEL, HOLD, and WP pins high */
gpio_set(drv->gpio_hold);
gpio_set(drv->gpio_wp);
/* Set GPIO pins as outputs. */
gpio_output(drv->gpio_hold);
gpio_output(drv->gpio_wp);
}

View File

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

View File

@ -197,7 +197,7 @@ typedef struct tagSXsvfInfo
} SXsvfInfo; } SXsvfInfo;
/* Declare pointer to functions that perform XSVF commands */ /* Declare pointer to functions that perform XSVF commands */
typedef int (*TXsvfDoCmdFuncPtr)( SXsvfInfo* ); typedef int (*TXsvfDoCmdFuncPtr)( jtag_gpio_t* const gpio, SXsvfInfo* );
/*============================================================================ /*============================================================================
@ -267,24 +267,24 @@ typedef int (*TXsvfDoCmdFuncPtr)( SXsvfInfo* );
* XSVF Function Prototypes * XSVF Function Prototypes
============================================================================*/ ============================================================================*/
int xsvfDoIllegalCmd( SXsvfInfo* pXsvfInfo ); /* Illegal command function */ int xsvfDoIllegalCmd( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo ); /* Illegal command function */
int xsvfDoXCOMPLETE( SXsvfInfo* pXsvfInfo ); int xsvfDoXCOMPLETE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXTDOMASK( SXsvfInfo* pXsvfInfo ); int xsvfDoXTDOMASK( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSIR( SXsvfInfo* pXsvfInfo ); int xsvfDoXSIR( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSIR2( SXsvfInfo* pXsvfInfo ); int xsvfDoXSIR2( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSDR( SXsvfInfo* pXsvfInfo ); int xsvfDoXSDR( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXRUNTEST( SXsvfInfo* pXsvfInfo ); int xsvfDoXRUNTEST( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXREPEAT( SXsvfInfo* pXsvfInfo ); int xsvfDoXREPEAT( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSDRSIZE( SXsvfInfo* pXsvfInfo ); int xsvfDoXSDRSIZE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSDRTDO( SXsvfInfo* pXsvfInfo ); int xsvfDoXSDRTDO( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSETSDRMASKS( SXsvfInfo* pXsvfInfo ); int xsvfDoXSETSDRMASKS( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSDRINC( SXsvfInfo* pXsvfInfo ); int xsvfDoXSDRINC( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSDRBCE( SXsvfInfo* pXsvfInfo ); int xsvfDoXSDRBCE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSDRTDOBCE( SXsvfInfo* pXsvfInfo ); int xsvfDoXSDRTDOBCE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXSTATE( SXsvfInfo* pXsvfInfo ); int xsvfDoXSTATE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXENDXR( SXsvfInfo* pXsvfInfo ); int xsvfDoXENDXR( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXCOMMENT( SXsvfInfo* pXsvfInfo ); int xsvfDoXCOMMENT( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
int xsvfDoXWAIT( SXsvfInfo* pXsvfInfo ); int xsvfDoXWAIT( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo );
/* Insert new command functions here */ /* Insert new command functions here */
/*============================================================================ /*============================================================================
@ -476,11 +476,11 @@ short xsvfGetAsNumBytes( long lNumBits )
* Parameters: sTms - new TMS value. * Parameters: sTms - new TMS value.
* Returns: void. * Returns: void.
*****************************************************************************/ *****************************************************************************/
void xsvfTmsTransition( short sTms ) void xsvfTmsTransition(jtag_gpio_t* const gpio, short sTms )
{ {
setPort( TMS, sTms ); setPort(gpio, TMS, sTms );
setPort( TCK, 0 ); setPort(gpio, TCK, 0 );
setPort( TCK, 1 ); setPort(gpio, TCK, 1 );
} }
/***************************************************************************** /*****************************************************************************
@ -496,7 +496,8 @@ void xsvfTmsTransition( short sTms )
* ucTargetState - New target TAP state. * ucTargetState - New target TAP state.
* Returns: int - 0 = success; otherwise error. * Returns: int - 0 = success; otherwise error.
*****************************************************************************/ *****************************************************************************/
int xsvfGotoTapState( unsigned char* pucTapState, int xsvfGotoTapState( jtag_gpio_t* const gpio,
unsigned char* pucTapState,
unsigned char ucTargetState ) unsigned char ucTargetState )
{ {
int i; int i;
@ -506,11 +507,11 @@ int xsvfGotoTapState( unsigned char* pucTapState,
if ( ucTargetState == XTAPSTATE_RESET ) if ( ucTargetState == XTAPSTATE_RESET )
{ {
/* If RESET, always perform TMS reset sequence to reset/sync TAPs */ /* If RESET, always perform TMS reset sequence to reset/sync TAPs */
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
for ( i = 0; i < 5; ++i ) for ( i = 0; i < 5; ++i )
{ {
setPort( TCK, 0 ); setPort(gpio, TCK, 0 );
setPort( TCK, 1 ); setPort(gpio, TCK, 1 );
} }
*pucTapState = XTAPSTATE_RESET; *pucTapState = XTAPSTATE_RESET;
XSVFDBG_PRINTF( 3, " TMS Reset Sequence -> Test-Logic-Reset\n" ); XSVFDBG_PRINTF( 3, " TMS Reset Sequence -> Test-Logic-Reset\n" );
@ -532,14 +533,14 @@ int xsvfGotoTapState( unsigned char* pucTapState,
or in IRPAUSE to comply with SVF standard */ or in IRPAUSE to comply with SVF standard */
if ( ucTargetState == XTAPSTATE_PAUSEDR ) if ( ucTargetState == XTAPSTATE_PAUSEDR )
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_EXIT2DR; *pucTapState = XTAPSTATE_EXIT2DR;
XSVFDBG_PRINTF1( 3, " TAP State = %s\n", XSVFDBG_PRINTF1( 3, " TAP State = %s\n",
xsvf_pzTapState[ *pucTapState ] ); xsvf_pzTapState[ *pucTapState ] );
} }
else if ( ucTargetState == XTAPSTATE_PAUSEIR ) else if ( ucTargetState == XTAPSTATE_PAUSEIR )
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_EXIT2IR; *pucTapState = XTAPSTATE_EXIT2IR;
XSVFDBG_PRINTF1( 3, " TAP State = %s\n", XSVFDBG_PRINTF1( 3, " TAP State = %s\n",
xsvf_pzTapState[ *pucTapState ] ); xsvf_pzTapState[ *pucTapState ] );
@ -552,138 +553,138 @@ int xsvfGotoTapState( unsigned char* pucTapState,
switch ( *pucTapState ) switch ( *pucTapState )
{ {
case XTAPSTATE_RESET: case XTAPSTATE_RESET:
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_RUNTEST; *pucTapState = XTAPSTATE_RUNTEST;
break; break;
case XTAPSTATE_RUNTEST: case XTAPSTATE_RUNTEST:
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_SELECTDR; *pucTapState = XTAPSTATE_SELECTDR;
break; break;
case XTAPSTATE_SELECTDR: case XTAPSTATE_SELECTDR:
if ( ucTargetState >= XTAPSTATE_IRSTATES ) if ( ucTargetState >= XTAPSTATE_IRSTATES )
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_SELECTIR; *pucTapState = XTAPSTATE_SELECTIR;
} }
else else
{ {
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_CAPTUREDR; *pucTapState = XTAPSTATE_CAPTUREDR;
} }
break; break;
case XTAPSTATE_CAPTUREDR: case XTAPSTATE_CAPTUREDR:
if ( ucTargetState == XTAPSTATE_SHIFTDR ) if ( ucTargetState == XTAPSTATE_SHIFTDR )
{ {
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_SHIFTDR; *pucTapState = XTAPSTATE_SHIFTDR;
} }
else else
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_EXIT1DR; *pucTapState = XTAPSTATE_EXIT1DR;
} }
break; break;
case XTAPSTATE_SHIFTDR: case XTAPSTATE_SHIFTDR:
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_EXIT1DR; *pucTapState = XTAPSTATE_EXIT1DR;
break; break;
case XTAPSTATE_EXIT1DR: case XTAPSTATE_EXIT1DR:
if ( ucTargetState == XTAPSTATE_PAUSEDR ) if ( ucTargetState == XTAPSTATE_PAUSEDR )
{ {
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_PAUSEDR; *pucTapState = XTAPSTATE_PAUSEDR;
} }
else else
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_UPDATEDR; *pucTapState = XTAPSTATE_UPDATEDR;
} }
break; break;
case XTAPSTATE_PAUSEDR: case XTAPSTATE_PAUSEDR:
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_EXIT2DR; *pucTapState = XTAPSTATE_EXIT2DR;
break; break;
case XTAPSTATE_EXIT2DR: case XTAPSTATE_EXIT2DR:
if ( ucTargetState == XTAPSTATE_SHIFTDR ) if ( ucTargetState == XTAPSTATE_SHIFTDR )
{ {
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_SHIFTDR; *pucTapState = XTAPSTATE_SHIFTDR;
} }
else else
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_UPDATEDR; *pucTapState = XTAPSTATE_UPDATEDR;
} }
break; break;
case XTAPSTATE_UPDATEDR: case XTAPSTATE_UPDATEDR:
if ( ucTargetState == XTAPSTATE_RUNTEST ) if ( ucTargetState == XTAPSTATE_RUNTEST )
{ {
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_RUNTEST; *pucTapState = XTAPSTATE_RUNTEST;
} }
else else
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_SELECTDR; *pucTapState = XTAPSTATE_SELECTDR;
} }
break; break;
case XTAPSTATE_SELECTIR: case XTAPSTATE_SELECTIR:
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_CAPTUREIR; *pucTapState = XTAPSTATE_CAPTUREIR;
break; break;
case XTAPSTATE_CAPTUREIR: case XTAPSTATE_CAPTUREIR:
if ( ucTargetState == XTAPSTATE_SHIFTIR ) if ( ucTargetState == XTAPSTATE_SHIFTIR )
{ {
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_SHIFTIR; *pucTapState = XTAPSTATE_SHIFTIR;
} }
else else
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_EXIT1IR; *pucTapState = XTAPSTATE_EXIT1IR;
} }
break; break;
case XTAPSTATE_SHIFTIR: case XTAPSTATE_SHIFTIR:
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_EXIT1IR; *pucTapState = XTAPSTATE_EXIT1IR;
break; break;
case XTAPSTATE_EXIT1IR: case XTAPSTATE_EXIT1IR:
if ( ucTargetState == XTAPSTATE_PAUSEIR ) if ( ucTargetState == XTAPSTATE_PAUSEIR )
{ {
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_PAUSEIR; *pucTapState = XTAPSTATE_PAUSEIR;
} }
else else
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_UPDATEIR; *pucTapState = XTAPSTATE_UPDATEIR;
} }
break; break;
case XTAPSTATE_PAUSEIR: case XTAPSTATE_PAUSEIR:
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_EXIT2IR; *pucTapState = XTAPSTATE_EXIT2IR;
break; break;
case XTAPSTATE_EXIT2IR: case XTAPSTATE_EXIT2IR:
if ( ucTargetState == XTAPSTATE_SHIFTIR ) if ( ucTargetState == XTAPSTATE_SHIFTIR )
{ {
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_SHIFTIR; *pucTapState = XTAPSTATE_SHIFTIR;
} }
else else
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_UPDATEIR; *pucTapState = XTAPSTATE_UPDATEIR;
} }
break; break;
case XTAPSTATE_UPDATEIR: case XTAPSTATE_UPDATEIR:
if ( ucTargetState == XTAPSTATE_RUNTEST ) if ( ucTargetState == XTAPSTATE_RUNTEST )
{ {
xsvfTmsTransition( 0 ); xsvfTmsTransition( gpio, 0 );
*pucTapState = XTAPSTATE_RUNTEST; *pucTapState = XTAPSTATE_RUNTEST;
} }
else else
{ {
xsvfTmsTransition( 1 ); xsvfTmsTransition( gpio, 1 );
*pucTapState = XTAPSTATE_SELECTDR; *pucTapState = XTAPSTATE_SELECTDR;
} }
break; break;
@ -714,7 +715,8 @@ int xsvfGotoTapState( unsigned char* pucTapState,
* iExitShift - 1=exit at end of shift; 0=stay in Shift-DR. * iExitShift - 1=exit at end of shift; 0=stay in Shift-DR.
* Returns: void. * Returns: void.
*****************************************************************************/ *****************************************************************************/
void xsvfShiftOnly( long lNumBits, void xsvfShiftOnly( jtag_gpio_t* const gpio,
long lNumBits,
lenVal* plvTdi, lenVal* plvTdi,
lenVal* plvTdoCaptured, lenVal* plvTdoCaptured,
int iExitShift ) int iExitShift )
@ -749,25 +751,25 @@ void xsvfShiftOnly( long lNumBits,
if ( iExitShift && !lNumBits ) if ( iExitShift && !lNumBits )
{ {
/* Exit Shift-DR state */ /* Exit Shift-DR state */
setPort( TMS, 1 ); setPort(gpio, TMS, 1 );
} }
/* Set the new TDI value */ /* Set the new TDI value */
setPort( TDI, (short)(ucTdiByte & 1) ); setPort(gpio, TDI, (short)(ucTdiByte & 1) );
ucTdiByte >>= 1; ucTdiByte >>= 1;
/* Set TCK low */ /* Set TCK low */
setPort( TCK, 0 ); setPort(gpio, TCK, 0 );
if ( pucTdo ) if ( pucTdo )
{ {
/* Save the TDO value */ /* Save the TDO value */
ucTdoBit = readTDOBit(); ucTdoBit = readTDOBit(gpio);
ucTdoByte |= ( ucTdoBit << i ); ucTdoByte |= ( ucTdoBit << i );
} }
/* Set TCK high */ /* Set TCK high */
setPort( TCK, 1 ); setPort(gpio, TCK, 1 );
} }
/* Save the TDO byte value */ /* Save the TDO byte value */
@ -802,7 +804,8 @@ void xsvfShiftOnly( long lNumBits,
* Skip the waitTime() if plvTdoMask->val[0:plvTdoMask->len-1] * Skip the waitTime() if plvTdoMask->val[0:plvTdoMask->len-1]
* is NOT all zeros and sMatch==1. * is NOT all zeros and sMatch==1.
*****************************************************************************/ *****************************************************************************/
int xsvfShift( unsigned char* pucTapState, int xsvfShift( jtag_gpio_t* const gpio,
unsigned char* pucTapState,
unsigned char ucStartState, unsigned char ucStartState,
long lNumBits, long lNumBits,
lenVal* plvTdi, lenVal* plvTdi,
@ -837,9 +840,9 @@ int xsvfShift( unsigned char* pucTapState,
if ( lRunTestTime ) if ( lRunTestTime )
{ {
/* Wait for prespecified XRUNTEST time */ /* Wait for prespecified XRUNTEST time */
xsvfGotoTapState( pucTapState, XTAPSTATE_RUNTEST ); xsvfGotoTapState( gpio, pucTapState, XTAPSTATE_RUNTEST );
XSVFDBG_PRINTF1( 3, " Wait = %ld usec\n", lRunTestTime ); XSVFDBG_PRINTF1( 3, " Wait = %ld usec\n", lRunTestTime );
waitTime( lRunTestTime ); waitTime( gpio, lRunTestTime );
} }
} }
else else
@ -847,10 +850,10 @@ int xsvfShift( unsigned char* pucTapState,
do do
{ {
/* Goto Shift-DR or Shift-IR */ /* Goto Shift-DR or Shift-IR */
xsvfGotoTapState( pucTapState, ucStartState ); xsvfGotoTapState( gpio, pucTapState, ucStartState );
/* Shift TDI and capture TDO */ /* Shift TDI and capture TDO */
xsvfShiftOnly( lNumBits, plvTdi, plvTdoCaptured, iExitShift ); xsvfShiftOnly( gpio, lNumBits, plvTdi, plvTdoCaptured, iExitShift );
if ( plvTdoExpected ) if ( plvTdoExpected )
{ {
@ -880,24 +883,24 @@ int xsvfShift( unsigned char* pucTapState,
XSVFDBG_PRINTF( 4, "\n"); XSVFDBG_PRINTF( 4, "\n");
XSVFDBG_PRINTF1( 3, " Retry #%d\n", ( ucRepeat + 1 ) ); XSVFDBG_PRINTF1( 3, " Retry #%d\n", ( ucRepeat + 1 ) );
/* Do exception handling retry - ShiftDR only */ /* Do exception handling retry - ShiftDR only */
xsvfGotoTapState( pucTapState, XTAPSTATE_PAUSEDR ); xsvfGotoTapState( gpio, pucTapState, XTAPSTATE_PAUSEDR );
/* Shift 1 extra bit */ /* Shift 1 extra bit */
xsvfGotoTapState( pucTapState, XTAPSTATE_SHIFTDR ); xsvfGotoTapState( gpio, pucTapState, XTAPSTATE_SHIFTDR );
/* Increment RUNTEST time by an additional 25% */ /* Increment RUNTEST time by an additional 25% */
lRunTestTime += ( lRunTestTime >> 2 ); lRunTestTime += ( lRunTestTime >> 2 );
} }
else else
{ {
/* Do normal exit from Shift-XR */ /* Do normal exit from Shift-XR */
xsvfGotoTapState( pucTapState, ucEndState ); xsvfGotoTapState( gpio, pucTapState, ucEndState );
} }
if ( lRunTestTime ) if ( lRunTestTime )
{ {
/* Wait for prespecified XRUNTEST time */ /* Wait for prespecified XRUNTEST time */
xsvfGotoTapState( pucTapState, XTAPSTATE_RUNTEST ); xsvfGotoTapState( gpio, pucTapState, XTAPSTATE_RUNTEST );
XSVFDBG_PRINTF1( 3, " Wait = %ld usec\n", lRunTestTime ); XSVFDBG_PRINTF1( 3, " Wait = %ld usec\n", lRunTestTime );
waitTime( lRunTestTime ); waitTime( gpio, lRunTestTime );
} }
} }
} while ( iMismatch && ( ucRepeat++ < ucMaxRepeat ) ); } while ( iMismatch && ( ucRepeat++ < ucMaxRepeat ) );
@ -941,7 +944,8 @@ int xsvfShift( unsigned char* pucTapState,
* ucMaxRepeat - maximum xc9500/xl retries. * ucMaxRepeat - maximum xc9500/xl retries.
* Returns: int - 0 = success; otherwise TDO mismatch. * Returns: int - 0 = success; otherwise TDO mismatch.
*****************************************************************************/ *****************************************************************************/
int xsvfBasicXSDRTDO( unsigned char* pucTapState, int xsvfBasicXSDRTDO( jtag_gpio_t* const gpio,
unsigned char* pucTapState,
long lShiftLengthBits, long lShiftLengthBits,
short sShiftLengthBytes, short sShiftLengthBytes,
lenVal* plvTdi, lenVal* plvTdi,
@ -957,7 +961,7 @@ int xsvfBasicXSDRTDO( unsigned char* pucTapState,
{ {
readVal( plvTdoExpected, sShiftLengthBytes ); readVal( plvTdoExpected, sShiftLengthBytes );
} }
return( xsvfShift( pucTapState, XTAPSTATE_SHIFTDR, lShiftLengthBits, return( xsvfShift( gpio, pucTapState, XTAPSTATE_SHIFTDR, lShiftLengthBits,
plvTdi, plvTdoCaptured, plvTdoExpected, plvTdoMask, plvTdi, plvTdoCaptured, plvTdoExpected, plvTdoMask,
ucEndState, lRunTestTime, ucMaxRepeat ) ); ucEndState, lRunTestTime, ucMaxRepeat ) );
} }
@ -1052,8 +1056,9 @@ void xsvfDoSDRMasking( lenVal* plvTdi,
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoIllegalCmd( SXsvfInfo* pXsvfInfo ) int xsvfDoIllegalCmd( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
(void)gpio;
XSVFDBG_PRINTF2( 0, "ERROR: Encountered unsupported command #%d (%s)\n", XSVFDBG_PRINTF2( 0, "ERROR: Encountered unsupported command #%d (%s)\n",
((unsigned int)(pXsvfInfo->ucCommand)), ((unsigned int)(pXsvfInfo->ucCommand)),
((pXsvfInfo->ucCommand < XLASTCMD) ((pXsvfInfo->ucCommand < XLASTCMD)
@ -1070,8 +1075,9 @@ int xsvfDoIllegalCmd( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXCOMPLETE( SXsvfInfo* pXsvfInfo ) int xsvfDoXCOMPLETE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
(void)gpio;
pXsvfInfo->ucComplete = 1; pXsvfInfo->ucComplete = 1;
return( XSVF_ERROR_NONE ); return( XSVF_ERROR_NONE );
} }
@ -1083,8 +1089,9 @@ int xsvfDoXCOMPLETE( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXTDOMASK( SXsvfInfo* pXsvfInfo ) int xsvfDoXTDOMASK( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
(void)gpio;
readVal( &(pXsvfInfo->lvTdoMask), pXsvfInfo->sShiftLengthBytes ); readVal( &(pXsvfInfo->lvTdoMask), pXsvfInfo->sShiftLengthBytes );
XSVFDBG_PRINTF( 4, " TDO Mask = "); XSVFDBG_PRINTF( 4, " TDO Mask = ");
XSVFDBG_PRINTLENVAL( 4, &(pXsvfInfo->lvTdoMask) ); XSVFDBG_PRINTLENVAL( 4, &(pXsvfInfo->lvTdoMask) );
@ -1101,7 +1108,7 @@ int xsvfDoXTDOMASK( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXSIR( SXsvfInfo* pXsvfInfo ) int xsvfDoXSIR( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
unsigned char ucShiftIrBits; unsigned char ucShiftIrBits;
short sShiftIrBytes; short sShiftIrBytes;
@ -1123,7 +1130,7 @@ int xsvfDoXSIR( SXsvfInfo* pXsvfInfo )
readVal( &(pXsvfInfo->lvTdi), xsvfGetAsNumBytes( ucShiftIrBits ) ); readVal( &(pXsvfInfo->lvTdi), xsvfGetAsNumBytes( ucShiftIrBits ) );
/* Shift the data */ /* Shift the data */
iErrorCode = xsvfShift( &(pXsvfInfo->ucTapState), XTAPSTATE_SHIFTIR, iErrorCode = xsvfShift( gpio, &(pXsvfInfo->ucTapState), XTAPSTATE_SHIFTIR,
ucShiftIrBits, &(pXsvfInfo->lvTdi), ucShiftIrBits, &(pXsvfInfo->lvTdi),
/*plvTdoCaptured*/0, /*plvTdoExpected*/0, /*plvTdoCaptured*/0, /*plvTdoExpected*/0,
/*plvTdoMask*/0, pXsvfInfo->ucEndIR, /*plvTdoMask*/0, pXsvfInfo->ucEndIR,
@ -1146,7 +1153,7 @@ int xsvfDoXSIR( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXSIR2( SXsvfInfo* pXsvfInfo ) int xsvfDoXSIR2( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
long lShiftIrBits; long lShiftIrBits;
short sShiftIrBytes; short sShiftIrBytes;
@ -1168,7 +1175,7 @@ int xsvfDoXSIR2( SXsvfInfo* pXsvfInfo )
readVal( &(pXsvfInfo->lvTdi), xsvfGetAsNumBytes( lShiftIrBits ) ); readVal( &(pXsvfInfo->lvTdi), xsvfGetAsNumBytes( lShiftIrBits ) );
/* Shift the data */ /* Shift the data */
iErrorCode = xsvfShift( &(pXsvfInfo->ucTapState), XTAPSTATE_SHIFTIR, iErrorCode = xsvfShift( gpio, &(pXsvfInfo->ucTapState), XTAPSTATE_SHIFTIR,
lShiftIrBits, &(pXsvfInfo->lvTdi), lShiftIrBits, &(pXsvfInfo->lvTdi),
/*plvTdoCaptured*/0, /*plvTdoExpected*/0, /*plvTdoCaptured*/0, /*plvTdoExpected*/0,
/*plvTdoMask*/0, pXsvfInfo->ucEndIR, /*plvTdoMask*/0, pXsvfInfo->ucEndIR,
@ -1192,12 +1199,12 @@ int xsvfDoXSIR2( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXSDR( SXsvfInfo* pXsvfInfo ) int xsvfDoXSDR( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
int iErrorCode; int iErrorCode;
readVal( &(pXsvfInfo->lvTdi), pXsvfInfo->sShiftLengthBytes ); readVal( &(pXsvfInfo->lvTdi), pXsvfInfo->sShiftLengthBytes );
/* use TDOExpected from last XSDRTDO instruction */ /* use TDOExpected from last XSDRTDO instruction */
iErrorCode = xsvfShift( &(pXsvfInfo->ucTapState), XTAPSTATE_SHIFTDR, iErrorCode = xsvfShift( gpio, &(pXsvfInfo->ucTapState), XTAPSTATE_SHIFTDR,
pXsvfInfo->lShiftLengthBits, &(pXsvfInfo->lvTdi), pXsvfInfo->lShiftLengthBits, &(pXsvfInfo->lvTdi),
&(pXsvfInfo->lvTdoCaptured), &(pXsvfInfo->lvTdoCaptured),
&(pXsvfInfo->lvTdoExpected), &(pXsvfInfo->lvTdoExpected),
@ -1217,8 +1224,9 @@ int xsvfDoXSDR( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXRUNTEST( SXsvfInfo* pXsvfInfo ) int xsvfDoXRUNTEST( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
(void)gpio;
readVal( &(pXsvfInfo->lvTdi), 4 ); readVal( &(pXsvfInfo->lvTdi), 4 );
pXsvfInfo->lRunTestTime = value( &(pXsvfInfo->lvTdi) ); pXsvfInfo->lRunTestTime = value( &(pXsvfInfo->lvTdi) );
XSVFDBG_PRINTF1( 3, " XRUNTEST = %ld\n", pXsvfInfo->lRunTestTime ); XSVFDBG_PRINTF1( 3, " XRUNTEST = %ld\n", pXsvfInfo->lRunTestTime );
@ -1232,8 +1240,9 @@ int xsvfDoXRUNTEST( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXREPEAT( SXsvfInfo* pXsvfInfo ) int xsvfDoXREPEAT( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
(void)gpio;
readByte( &(pXsvfInfo->ucMaxRepeat) ); readByte( &(pXsvfInfo->ucMaxRepeat) );
XSVFDBG_PRINTF1( 3, " XREPEAT = %d\n", XSVFDBG_PRINTF1( 3, " XREPEAT = %d\n",
((unsigned int)(pXsvfInfo->ucMaxRepeat)) ); ((unsigned int)(pXsvfInfo->ucMaxRepeat)) );
@ -1247,8 +1256,9 @@ int xsvfDoXREPEAT( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXSDRSIZE( SXsvfInfo* pXsvfInfo ) int xsvfDoXSDRSIZE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
(void)gpio;
int iErrorCode; int iErrorCode;
iErrorCode = XSVF_ERROR_NONE; iErrorCode = XSVF_ERROR_NONE;
readVal( &(pXsvfInfo->lvTdi), 4 ); readVal( &(pXsvfInfo->lvTdi), 4 );
@ -1272,10 +1282,10 @@ int xsvfDoXSDRSIZE( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXSDRTDO( SXsvfInfo* pXsvfInfo ) int xsvfDoXSDRTDO( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
int iErrorCode; int iErrorCode;
iErrorCode = xsvfBasicXSDRTDO( &(pXsvfInfo->ucTapState), iErrorCode = xsvfBasicXSDRTDO( gpio, &(pXsvfInfo->ucTapState),
pXsvfInfo->lShiftLengthBits, pXsvfInfo->lShiftLengthBits,
pXsvfInfo->sShiftLengthBytes, pXsvfInfo->sShiftLengthBytes,
&(pXsvfInfo->lvTdi), &(pXsvfInfo->lvTdi),
@ -1303,8 +1313,9 @@ int xsvfDoXSDRTDO( SXsvfInfo* pXsvfInfo )
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
#ifdef XSVF_SUPPORT_COMPRESSION #ifdef XSVF_SUPPORT_COMPRESSION
int xsvfDoXSETSDRMASKS( SXsvfInfo* pXsvfInfo ) int xsvfDoXSETSDRMASKS( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
(void)gpio;
/* read the addressMask */ /* read the addressMask */
readVal( &(pXsvfInfo->lvAddressMask), pXsvfInfo->sShiftLengthBytes ); readVal( &(pXsvfInfo->lvAddressMask), pXsvfInfo->sShiftLengthBytes );
/* read the dataMask */ /* read the dataMask */
@ -1338,7 +1349,7 @@ int xsvfDoXSETSDRMASKS( SXsvfInfo* pXsvfInfo )
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
#ifdef XSVF_SUPPORT_COMPRESSION #ifdef XSVF_SUPPORT_COMPRESSION
int xsvfDoXSDRINC( SXsvfInfo* pXsvfInfo ) int xsvfDoXSDRINC( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
int iErrorCode; int iErrorCode;
int iDataMaskLen; int iDataMaskLen;
@ -1347,7 +1358,7 @@ int xsvfDoXSDRINC( SXsvfInfo* pXsvfInfo )
unsigned char i; unsigned char i;
readVal( &(pXsvfInfo->lvTdi), pXsvfInfo->sShiftLengthBytes ); readVal( &(pXsvfInfo->lvTdi), pXsvfInfo->sShiftLengthBytes );
iErrorCode = xsvfShift( &(pXsvfInfo->ucTapState), XTAPSTATE_SHIFTDR, iErrorCode = xsvfShift( gpio, &(pXsvfInfo->ucTapState), XTAPSTATE_SHIFTDR,
pXsvfInfo->lShiftLengthBits, pXsvfInfo->lShiftLengthBits,
&(pXsvfInfo->lvTdi), &(pXsvfInfo->lvTdoCaptured), &(pXsvfInfo->lvTdi), &(pXsvfInfo->lvTdoCaptured),
&(pXsvfInfo->lvTdoExpected), &(pXsvfInfo->lvTdoExpected),
@ -1379,7 +1390,7 @@ int xsvfDoXSDRINC( SXsvfInfo* pXsvfInfo )
&(pXsvfInfo->lvNextData), &(pXsvfInfo->lvNextData),
&(pXsvfInfo->lvAddressMask), &(pXsvfInfo->lvAddressMask),
&(pXsvfInfo->lvDataMask) ); &(pXsvfInfo->lvDataMask) );
iErrorCode = xsvfShift( &(pXsvfInfo->ucTapState), iErrorCode = xsvfShift( gpio, &(pXsvfInfo->ucTapState),
XTAPSTATE_SHIFTDR, XTAPSTATE_SHIFTDR,
pXsvfInfo->lShiftLengthBits, pXsvfInfo->lShiftLengthBits,
&(pXsvfInfo->lvTdi), &(pXsvfInfo->lvTdi),
@ -1410,13 +1421,13 @@ int xsvfDoXSDRINC( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXSDRBCE( SXsvfInfo* pXsvfInfo ) int xsvfDoXSDRBCE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
unsigned char ucEndDR; unsigned char ucEndDR;
int iErrorCode; int iErrorCode;
ucEndDR = (unsigned char)(( pXsvfInfo->ucCommand == XSDRE ) ? ucEndDR = (unsigned char)(( pXsvfInfo->ucCommand == XSDRE ) ?
pXsvfInfo->ucEndDR : XTAPSTATE_SHIFTDR); pXsvfInfo->ucEndDR : XTAPSTATE_SHIFTDR);
iErrorCode = xsvfBasicXSDRTDO( &(pXsvfInfo->ucTapState), iErrorCode = xsvfBasicXSDRTDO( gpio, &(pXsvfInfo->ucTapState),
pXsvfInfo->lShiftLengthBits, pXsvfInfo->lShiftLengthBits,
pXsvfInfo->sShiftLengthBytes, pXsvfInfo->sShiftLengthBytes,
&(pXsvfInfo->lvTdi), &(pXsvfInfo->lvTdi),
@ -1441,13 +1452,13 @@ int xsvfDoXSDRBCE( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXSDRTDOBCE( SXsvfInfo* pXsvfInfo ) int xsvfDoXSDRTDOBCE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
unsigned char ucEndDR; unsigned char ucEndDR;
int iErrorCode; int iErrorCode;
ucEndDR = (unsigned char)(( pXsvfInfo->ucCommand == XSDRTDOE ) ? ucEndDR = (unsigned char)(( pXsvfInfo->ucCommand == XSDRTDOE ) ?
pXsvfInfo->ucEndDR : XTAPSTATE_SHIFTDR); pXsvfInfo->ucEndDR : XTAPSTATE_SHIFTDR);
iErrorCode = xsvfBasicXSDRTDO( &(pXsvfInfo->ucTapState), iErrorCode = xsvfBasicXSDRTDO( gpio, &(pXsvfInfo->ucTapState),
pXsvfInfo->lShiftLengthBits, pXsvfInfo->lShiftLengthBits,
pXsvfInfo->sShiftLengthBytes, pXsvfInfo->sShiftLengthBytes,
&(pXsvfInfo->lvTdi), &(pXsvfInfo->lvTdi),
@ -1470,12 +1481,12 @@ int xsvfDoXSDRTDOBCE( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXSTATE( SXsvfInfo* pXsvfInfo ) int xsvfDoXSTATE( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
unsigned char ucNextState; unsigned char ucNextState;
int iErrorCode; int iErrorCode;
readByte( &ucNextState ); readByte( &ucNextState );
iErrorCode = xsvfGotoTapState( &(pXsvfInfo->ucTapState), ucNextState ); iErrorCode = xsvfGotoTapState( gpio, &(pXsvfInfo->ucTapState), ucNextState );
if ( iErrorCode != XSVF_ERROR_NONE ) if ( iErrorCode != XSVF_ERROR_NONE )
{ {
pXsvfInfo->iErrorCode = iErrorCode; pXsvfInfo->iErrorCode = iErrorCode;
@ -1492,8 +1503,9 @@ int xsvfDoXSTATE( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXENDXR( SXsvfInfo* pXsvfInfo ) int xsvfDoXENDXR( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
(void)gpio;
int iErrorCode; int iErrorCode;
unsigned char ucEndState; unsigned char ucEndState;
@ -1549,8 +1561,10 @@ int xsvfDoXENDXR( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXCOMMENT( SXsvfInfo* pXsvfInfo ) int xsvfDoXCOMMENT( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
(void)gpio;
/* Use the comment for debugging */ /* Use the comment for debugging */
/* Otherwise, read through the comment to the end '\0' and ignore */ /* Otherwise, read through the comment to the end '\0' and ignore */
unsigned char ucText; unsigned char ucText;
@ -1587,7 +1601,7 @@ int xsvfDoXCOMMENT( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - XSVF information pointer. * Parameters: pXsvfInfo - XSVF information pointer.
* Returns: int - 0 = success; non-zero = error. * Returns: int - 0 = success; non-zero = error.
*****************************************************************************/ *****************************************************************************/
int xsvfDoXWAIT( SXsvfInfo* pXsvfInfo ) int xsvfDoXWAIT( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
unsigned char ucWaitState; unsigned char ucWaitState;
unsigned char ucEndState; unsigned char ucEndState;
@ -1611,16 +1625,16 @@ int xsvfDoXWAIT( SXsvfInfo* pXsvfInfo )
/* If not already in <wait_state>, go to <wait_state> */ /* If not already in <wait_state>, go to <wait_state> */
if ( pXsvfInfo->ucTapState != ucWaitState ) if ( pXsvfInfo->ucTapState != ucWaitState )
{ {
xsvfGotoTapState( &(pXsvfInfo->ucTapState), ucWaitState ); xsvfGotoTapState( gpio, &(pXsvfInfo->ucTapState), ucWaitState );
} }
/* Wait for <wait_time> microseconds */ /* Wait for <wait_time> microseconds */
waitTime( lWaitTime ); waitTime( gpio, lWaitTime );
/* If not already in <end_state>, go to <end_state> */ /* If not already in <end_state>, go to <end_state> */
if ( pXsvfInfo->ucTapState != ucEndState ) if ( pXsvfInfo->ucTapState != ucEndState )
{ {
xsvfGotoTapState( &(pXsvfInfo->ucTapState), ucEndState ); xsvfGotoTapState( gpio, &(pXsvfInfo->ucTapState), ucEndState );
} }
return( XSVF_ERROR_NONE ); return( XSVF_ERROR_NONE );
@ -1641,7 +1655,7 @@ int xsvfDoXWAIT( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - ptr to the XSVF information. * Parameters: pXsvfInfo - ptr to the XSVF information.
* Returns: int - 0 = success; otherwise error. * Returns: int - 0 = success; otherwise error.
*****************************************************************************/ *****************************************************************************/
int xsvfInitialize( SXsvfInfo* pXsvfInfo ) int xsvfInitialize( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
/* Initialize values */ /* Initialize values */
pXsvfInfo->iErrorCode = xsvfInfoInit( pXsvfInfo ); pXsvfInfo->iErrorCode = xsvfInfoInit( pXsvfInfo );
@ -1649,7 +1663,7 @@ int xsvfInitialize( SXsvfInfo* pXsvfInfo )
if ( !pXsvfInfo->iErrorCode ) if ( !pXsvfInfo->iErrorCode )
{ {
/* Initialize the TAPs */ /* Initialize the TAPs */
pXsvfInfo->iErrorCode = xsvfGotoTapState( &(pXsvfInfo->ucTapState), pXsvfInfo->iErrorCode = xsvfGotoTapState( gpio, &(pXsvfInfo->ucTapState),
XTAPSTATE_RESET ); XTAPSTATE_RESET );
} }
@ -1666,7 +1680,7 @@ int xsvfInitialize( SXsvfInfo* pXsvfInfo )
* Parameters: pXsvfInfo - ptr to the XSVF information. * Parameters: pXsvfInfo - ptr to the XSVF information.
* Returns: int - 0 = success; otherwise error. * Returns: int - 0 = success; otherwise error.
*****************************************************************************/ *****************************************************************************/
int xsvfRun( SXsvfInfo* pXsvfInfo ) int xsvfRun( jtag_gpio_t* const gpio, SXsvfInfo* pXsvfInfo )
{ {
/* Process the XSVF commands */ /* Process the XSVF commands */
if ( (!pXsvfInfo->iErrorCode) && (!pXsvfInfo->ucComplete) ) if ( (!pXsvfInfo->iErrorCode) && (!pXsvfInfo->ucComplete) )
@ -1682,12 +1696,12 @@ int xsvfRun( SXsvfInfo* pXsvfInfo )
xsvf_pzCommandName[pXsvfInfo->ucCommand] ); xsvf_pzCommandName[pXsvfInfo->ucCommand] );
/* If your compiler cannot take this form, /* If your compiler cannot take this form,
then convert to a switch statement */ then convert to a switch statement */
xsvf_pfDoCmd[ pXsvfInfo->ucCommand ]( pXsvfInfo ); xsvf_pfDoCmd[ pXsvfInfo->ucCommand ]( gpio, pXsvfInfo );
} }
else else
{ {
/* Illegal command value. Func sets error code. */ /* Illegal command value. Func sets error code. */
xsvfDoIllegalCmd( pXsvfInfo ); xsvfDoIllegalCmd( gpio, pXsvfInfo );
} }
} }
@ -1717,15 +1731,15 @@ void xsvfCleanup( SXsvfInfo* pXsvfInfo )
* Parameters: none. * Parameters: none.
* Returns: int - Legacy result values: 1 == success; 0 == failed. * Returns: int - Legacy result values: 1 == success; 0 == failed.
*****************************************************************************/ *****************************************************************************/
int xsvfExecute() int xsvfExecute(jtag_gpio_t* const gpio)
{ {
SXsvfInfo xsvfInfo; SXsvfInfo xsvfInfo;
xsvfInitialize( &xsvfInfo ); xsvfInitialize( gpio, &xsvfInfo );
while ( !xsvfInfo.iErrorCode && (!xsvfInfo.ucComplete) ) while ( !xsvfInfo.iErrorCode && (!xsvfInfo.ucComplete) )
{ {
xsvfRun( &xsvfInfo ); xsvfRun( gpio, &xsvfInfo );
} }
if ( xsvfInfo.iErrorCode ) if ( xsvfInfo.iErrorCode )

View File

@ -13,6 +13,8 @@
#ifndef XSVF_MICRO_H #ifndef XSVF_MICRO_H
#define XSVF_MICRO_H #define XSVF_MICRO_H
#include "cpld_jtag.h"
/* Legacy error codes for xsvfExecute from original XSVF player v2.0 */ /* Legacy error codes for xsvfExecute from original XSVF player v2.0 */
#define XSVF_LEGACY_SUCCESS 1 #define XSVF_LEGACY_SUCCESS 1
#define XSVF_LEGACY_ERROR 0 #define XSVF_LEGACY_ERROR 0
@ -36,7 +38,7 @@
* Parameters: none. * Parameters: none.
* Returns: int - For error codes see above. * Returns: int - For error codes see above.
*****************************************************************************/ *****************************************************************************/
extern int xsvfExecute(); extern int xsvfExecute(jtag_gpio_t* const gpio);
#endif /* XSVF_MICRO_H */ #endif /* XSVF_MICRO_H */

View File

@ -13,7 +13,8 @@
#include "hackrf_core.h" #include "hackrf_core.h"
#include "cpld_jtag.h" #include "cpld_jtag.h"
#include <libopencm3/lpc43xx/gpio.h>
#include "gpio.h"
void delay_jtag(uint32_t duration) void delay_jtag(uint32_t duration)
{ {
@ -38,23 +39,23 @@ void delay_jtag(uint32_t duration)
/* setPort: Implement to set the named JTAG signal (p) to the new value (v).*/ /* setPort: Implement to set the named JTAG signal (p) to the new value (v).*/
/* if in debugging mode, then just set the variables */ /* if in debugging mode, then just set the variables */
void setPort(short p,short val) void setPort(jtag_gpio_t* const gpio, short p, short val)
{ {
if (p==TMS) { if (p==TMS) {
if (val) if (val)
gpio_set(PORT_CPLD_TMS, PIN_CPLD_TMS); gpio_set(gpio->gpio_tms);
else else
gpio_clear(PORT_CPLD_TMS, PIN_CPLD_TMS); gpio_clear(gpio->gpio_tms);
} if (p==TDI) { } if (p==TDI) {
if (val) if (val)
gpio_set(PORT_CPLD_TDI, PIN_CPLD_TDI); gpio_set(gpio->gpio_tdi);
else else
gpio_clear(PORT_CPLD_TDI, PIN_CPLD_TDI); gpio_clear(gpio->gpio_tdi);
} if (p==TCK) { } if (p==TCK) {
if (val) if (val)
gpio_set(PORT_CPLD_TCK, PIN_CPLD_TCK); gpio_set(gpio->gpio_tck);
else else
gpio_clear(PORT_CPLD_TCK, PIN_CPLD_TCK); gpio_clear(gpio->gpio_tck);
} }
/* conservative delay */ /* conservative delay */
@ -63,11 +64,11 @@ void setPort(short p,short val)
/* toggle tck LH. No need to modify this code. It is output via setPort. */ /* toggle tck LH. No need to modify this code. It is output via setPort. */
void pulseClock() void pulseClock(jtag_gpio_t* const gpio)
{ {
setPort(TCK,0); /* set the TCK port to low */ setPort(gpio, TCK,0); /* set the TCK port to low */
delay_jtag(200); delay_jtag(200);
setPort(TCK,1); /* set the TCK port to high */ setPort(gpio, TCK,1); /* set the TCK port to high */
delay_jtag(200); delay_jtag(200);
} }
@ -81,10 +82,10 @@ void readByte(unsigned char *data)
/* readTDOBit: Implement to return the current value of the JTAG TDO signal.*/ /* readTDOBit: Implement to return the current value of the JTAG TDO signal.*/
/* read the TDO bit from port */ /* read the TDO bit from port */
unsigned char readTDOBit() unsigned char readTDOBit(jtag_gpio_t* const gpio)
{ {
delay_jtag(2000); delay_jtag(2000);
return CPLD_TDO_STATE; return gpio_read(gpio->gpio_tdo);;
} }
/* waitTime: Implement as follows: */ /* waitTime: Implement as follows: */
@ -96,7 +97,7 @@ unsigned char readTDOBit()
/* RECOMMENDED IMPLEMENTATION: Pulse TCK at least microsec times AND */ /* RECOMMENDED IMPLEMENTATION: Pulse TCK at least microsec times AND */
/* continue pulsing TCK until the microsec wait */ /* continue pulsing TCK until the microsec wait */
/* requirement is also satisfied. */ /* requirement is also satisfied. */
void waitTime(long microsec) void waitTime(jtag_gpio_t* const gpio, long microsec)
{ {
static long tckCyclesPerMicrosec = 1; /* must be at least 1 */ static long tckCyclesPerMicrosec = 1; /* must be at least 1 */
long tckCycles = microsec * tckCyclesPerMicrosec; long tckCycles = microsec * tckCyclesPerMicrosec;
@ -108,6 +109,6 @@ void waitTime(long microsec)
in order to satisfy the microsec wait time requirement. */ in order to satisfy the microsec wait time requirement. */
for ( i = 0; i < tckCycles; ++i ) for ( i = 0; i < tckCycles; ++i )
{ {
pulseClock(); pulseClock(gpio);
} }
} }

View File

@ -7,6 +7,8 @@
#ifndef ports_dot_h #ifndef ports_dot_h
#define ports_dot_h #define ports_dot_h
#include "cpld_jtag.h"
/* these constants are used to send the appropriate ports to setPort */ /* these constants are used to send the appropriate ports to setPort */
/* they should be enumerated types, but some of the microcontroller */ /* they should be enumerated types, but some of the microcontroller */
/* compilers don't like enumerated types */ /* compilers don't like enumerated types */
@ -15,17 +17,17 @@
#define TDI (short) 2 #define TDI (short) 2
/* set the port "p" (TCK, TMS, or TDI) to val (0 or 1) */ /* set the port "p" (TCK, TMS, or TDI) to val (0 or 1) */
extern void setPort(short p, short val); extern void setPort(jtag_gpio_t* const gpio, short p, short val);
/* read the TDO bit and store it in val */ /* read the TDO bit and store it in val */
extern unsigned char readTDOBit(); extern unsigned char readTDOBit(jtag_gpio_t* const gpio);
/* make clock go down->up->down*/ /* make clock go down->up->down*/
extern void pulseClock(); extern void pulseClock(jtag_gpio_t* const gpio);
/* read the next byte of data from the xsvf file */ /* read the next byte of data from the xsvf file */
extern void readByte(unsigned char *data); extern void readByte(unsigned char *data);
extern void waitTime(long microsec); extern void waitTime(jtag_gpio_t* const gpio, long microsec);
#endif #endif

View File

@ -135,8 +135,18 @@ macro(DeclareTargets)
${PATH_HACKRF_FIRMWARE_COMMON}/rf_path.c ${PATH_HACKRF_FIRMWARE_COMMON}/rf_path.c
${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.c ${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.c
${PATH_HACKRF_FIRMWARE_COMMON}/max2837.c ${PATH_HACKRF_FIRMWARE_COMMON}/max2837.c
${PATH_HACKRF_FIRMWARE_COMMON}/max2837_target.c
${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c ${PATH_HACKRF_FIRMWARE_COMMON}/max5864.c
${PATH_HACKRF_FIRMWARE_COMMON}/max5864_target.c
${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071.c ${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071.c
${PATH_HACKRF_FIRMWARE_COMMON}/i2c_bus.c
${PATH_HACKRF_FIRMWARE_COMMON}/i2c_lpc.c
${PATH_HACKRF_FIRMWARE_COMMON}/rffc5071_spi.c
${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv.c
${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv_target.c
${PATH_HACKRF_FIRMWARE_COMMON}/spi_bus.c
${PATH_HACKRF_FIRMWARE_COMMON}/spi_ssp.c
${PATH_HACKRF_FIRMWARE_COMMON}/gpio_lpc.c
m0_bin.s m0_bin.s
) )

View File

@ -44,7 +44,6 @@ set(SRC_M4
usb_api_transceiver.c usb_api_transceiver.c
"${PATH_HACKRF_FIRMWARE_COMMON}/usb_queue.c" "${PATH_HACKRF_FIRMWARE_COMMON}/usb_queue.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/fault_handler.c" "${PATH_HACKRF_FIRMWARE_COMMON}/fault_handler.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/w25q80bv.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/cpld_jtag.c" "${PATH_HACKRF_FIRMWARE_COMMON}/cpld_jtag.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/lenval.c" "${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/lenval.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/micro.c" "${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/micro.c"

View File

@ -24,7 +24,6 @@
#include <libopencm3/cm3/vector.h> #include <libopencm3/cm3/vector.h>
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/m4/nvic.h> #include <libopencm3/lpc43xx/m4/nvic.h>
#include <streaming.h> #include <streaming.h>
@ -43,16 +42,13 @@
#include "usb_api_spiflash.h" #include "usb_api_spiflash.h"
#include "usb_api_transceiver.h" #include "usb_api_transceiver.h"
#include "rf_path.h"
#include "sgpio_isr.h" #include "sgpio_isr.h"
#include "usb_bulk_buffer.h" #include "usb_bulk_buffer.h"
#include "si5351c.h"
#include "w25q80bv.h"
static volatile transceiver_mode_t _transceiver_mode = TRANSCEIVER_MODE_OFF; static volatile transceiver_mode_t _transceiver_mode = TRANSCEIVER_MODE_OFF;
void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) { void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
baseband_streaming_disable(); baseband_streaming_disable(&sgpio_config);
usb_endpoint_disable(&usb_endpoint_bulk_in); usb_endpoint_disable(&usb_endpoint_bulk_in);
usb_endpoint_disable(&usb_endpoint_bulk_out); usb_endpoint_disable(&usb_endpoint_bulk_out);
@ -60,27 +56,27 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
_transceiver_mode = new_transceiver_mode; _transceiver_mode = new_transceiver_mode;
if( _transceiver_mode == TRANSCEIVER_MODE_RX ) { if( _transceiver_mode == TRANSCEIVER_MODE_RX ) {
gpio_clear(PORT_LED1_3, PIN_LED3); led_off(LED3);
gpio_set(PORT_LED1_3, PIN_LED2); led_on(LED2);
usb_endpoint_init(&usb_endpoint_bulk_in); usb_endpoint_init(&usb_endpoint_bulk_in);
rf_path_set_direction(RF_PATH_DIRECTION_RX); rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX);
vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx; vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx;
} else if (_transceiver_mode == TRANSCEIVER_MODE_TX) { } else if (_transceiver_mode == TRANSCEIVER_MODE_TX) {
gpio_clear(PORT_LED1_3, PIN_LED2); led_off(LED2);
gpio_set(PORT_LED1_3, PIN_LED3); led_on(LED3);
usb_endpoint_init(&usb_endpoint_bulk_out); usb_endpoint_init(&usb_endpoint_bulk_out);
rf_path_set_direction(RF_PATH_DIRECTION_TX); rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_TX);
vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_tx; vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_tx;
} else { } else {
gpio_clear(PORT_LED1_3, PIN_LED2); led_off(LED2);
gpio_clear(PORT_LED1_3, PIN_LED3); led_off(LED3);
rf_path_set_direction(RF_PATH_DIRECTION_OFF); rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF);
vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx; vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx;
} }
if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) { if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) {
si5351c_activate_best_clock_source(); si5351c_activate_best_clock_source(&clock_gen);
baseband_streaming_enable(); baseband_streaming_enable(&sgpio_config);
} }
} }
@ -179,7 +175,7 @@ void usb_configuration_changed(
if( device->configuration->number == 1 ) { if( device->configuration->number == 1 ) {
// transceiver configuration // transceiver configuration
cpu_clock_pll1_max_speed(); cpu_clock_pll1_max_speed();
gpio_set(PORT_LED1_3, PIN_LED1); led_on(LED1);
} else if( device->configuration->number == 2 ) { } else if( device->configuration->number == 2 ) {
// CPLD update configuration // CPLD update configuration
cpu_clock_pll1_max_speed(); cpu_clock_pll1_max_speed();
@ -188,7 +184,7 @@ void usb_configuration_changed(
} else { } else {
/* Configuration number equal 0 means usb bus reset. */ /* Configuration number equal 0 means usb bus reset. */
cpu_clock_pll1_low_speed(); cpu_clock_pll1_low_speed();
gpio_clear(PORT_LED1_3, PIN_LED1); led_off(LED1);
} }
} }
@ -247,9 +243,7 @@ int main(void) {
usb_run(&usb_device); usb_run(&usb_device);
ssp1_init(); rf_path_init(&rf_path);
rf_path_init();
unsigned int phase = 0; unsigned int phase = 0;
while(true) { while(true) {

View File

@ -22,8 +22,6 @@
#include "usb_api_cpld.h" #include "usb_api_cpld.h"
#include <libopencm3/lpc43xx/gpio.h>
#include <hackrf_core.h> #include <hackrf_core.h>
#include <cpld_jtag.h> #include <cpld_jtag.h>
#include <usb_queue.h> #include <usb_queue.h>
@ -63,7 +61,6 @@ static void refill_cpld_buffer(void)
void cpld_update(void) void cpld_update(void)
{ {
#define WAIT_LOOP_DELAY (6000000) #define WAIT_LOOP_DELAY (6000000)
#define ALL_LEDS (PIN_LED1|PIN_LED2|PIN_LED3)
int i; int i;
int error; int error;
@ -72,7 +69,7 @@ void cpld_update(void)
refill_cpld_buffer(); refill_cpld_buffer();
error = cpld_jtag_program(sizeof(cpld_xsvf_buffer), error = cpld_jtag_program(&jtag_cpld, sizeof(cpld_xsvf_buffer),
cpld_xsvf_buffer, cpld_xsvf_buffer,
refill_cpld_buffer); refill_cpld_buffer);
if(error == 0) if(error == 0)
@ -80,17 +77,21 @@ void cpld_update(void)
/* blink LED1, LED2, and LED3 on success */ /* blink LED1, LED2, and LED3 on success */
while (1) while (1)
{ {
gpio_set(PORT_LED1_3, ALL_LEDS); /* LEDs on */ led_on(LED1);
led_on(LED2);
led_on(LED3);
for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
gpio_clear(PORT_LED1_3, ALL_LEDS); /* LEDs off */ led_off(LED1);
led_off(LED2);
led_off(LED3);
for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
} }
}else }else
{ {
/* LED3 (Red) steady on error */ /* LED3 (Red) steady on error */
gpio_set(PORT_LED1_3, PIN_LED3); /* LEDs on */ led_on(LED3);
while (1); while (1);
} }
} }

View File

@ -22,14 +22,16 @@
#include "usb_api_register.h" #include "usb_api_register.h"
#include <hackrf_core.h>
#include <usb_queue.h> #include <usb_queue.h>
#include <max2837.h> #include <max2837.h>
#include <si5351c.h>
#include <rffc5071.h> #include <rffc5071.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <hackrf_core.h>
usb_request_status_t usb_vendor_request_write_max2837( usb_request_status_t usb_vendor_request_write_max2837(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
@ -37,7 +39,7 @@ usb_request_status_t usb_vendor_request_write_max2837(
if( stage == USB_TRANSFER_STAGE_SETUP ) { if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < MAX2837_NUM_REGS ) { if( endpoint->setup.index < MAX2837_NUM_REGS ) {
if( endpoint->setup.value < MAX2837_DATA_REGS_MAX_VALUE ) { if( endpoint->setup.value < MAX2837_DATA_REGS_MAX_VALUE ) {
max2837_reg_write(endpoint->setup.index, endpoint->setup.value); max2837_reg_write(&max2837, endpoint->setup.index, endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
} }
@ -54,7 +56,7 @@ usb_request_status_t usb_vendor_request_read_max2837(
) { ) {
if( stage == USB_TRANSFER_STAGE_SETUP ) { if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < MAX2837_NUM_REGS ) { if( endpoint->setup.index < MAX2837_NUM_REGS ) {
const uint16_t value = max2837_reg_read(endpoint->setup.index); const uint16_t value = max2837_reg_read(&max2837, endpoint->setup.index);
endpoint->buffer[0] = value & 0xff; endpoint->buffer[0] = value & 0xff;
endpoint->buffer[1] = value >> 8; endpoint->buffer[1] = value >> 8;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2, usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2,
@ -75,7 +77,7 @@ usb_request_status_t usb_vendor_request_write_si5351c(
if( stage == USB_TRANSFER_STAGE_SETUP ) { if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < 256 ) { if( endpoint->setup.index < 256 ) {
if( endpoint->setup.value < 256 ) { if( endpoint->setup.value < 256 ) {
si5351c_write_single(endpoint->setup.index, endpoint->setup.value); si5351c_write_single(&clock_gen, endpoint->setup.index, endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
} }
@ -92,7 +94,7 @@ usb_request_status_t usb_vendor_request_read_si5351c(
) { ) {
if( stage == USB_TRANSFER_STAGE_SETUP ) { if( stage == USB_TRANSFER_STAGE_SETUP ) {
if( endpoint->setup.index < 256 ) { if( endpoint->setup.index < 256 ) {
const uint8_t value = si5351c_read_single(endpoint->setup.index); const uint8_t value = si5351c_read_single(&clock_gen, endpoint->setup.index);
endpoint->buffer[0] = value; endpoint->buffer[0] = value;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL); NULL, NULL);
@ -113,7 +115,7 @@ usb_request_status_t usb_vendor_request_write_rffc5071(
{ {
if( endpoint->setup.index < RFFC5071_NUM_REGS ) if( endpoint->setup.index < RFFC5071_NUM_REGS )
{ {
rffc5071_reg_write(endpoint->setup.index, endpoint->setup.value); rffc5071_reg_write(&rffc5072, endpoint->setup.index, endpoint->setup.value);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
} }
@ -132,7 +134,7 @@ usb_request_status_t usb_vendor_request_read_rffc5071(
{ {
if( endpoint->setup.index < RFFC5071_NUM_REGS ) if( endpoint->setup.index < RFFC5071_NUM_REGS )
{ {
value = rffc5071_reg_read(endpoint->setup.index); value = rffc5071_reg_read(&rffc5072, endpoint->setup.index);
endpoint->buffer[0] = value & 0xff; endpoint->buffer[0] = value & 0xff;
endpoint->buffer[1] = value >> 8; endpoint->buffer[1] = value >> 8;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2, usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2,

View File

@ -26,16 +26,21 @@
#include <stddef.h> #include <stddef.h>
#include <hackrf_core.h>
#include <w25q80bv.h> #include <w25q80bv.h>
uint8_t spiflash_buffer[W25Q80BV_PAGE_LEN]; /* Buffer size == spi_flash.page_len */
uint8_t spiflash_buffer[256U];
usb_request_status_t usb_vendor_request_erase_spiflash( usb_request_status_t usb_vendor_request_erase_spiflash(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{ {
if (stage == USB_TRANSFER_STAGE_SETUP) { if (stage == USB_TRANSFER_STAGE_SETUP) {
spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv);
w25q80bv_setup(&spi_flash);
/* only chip erase is implemented */ /* only chip erase is implemented */
w25q80bv_chip_erase(); w25q80bv_chip_erase(&spi_flash);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
} }
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
@ -50,23 +55,25 @@ usb_request_status_t usb_vendor_request_write_spiflash(
if (stage == USB_TRANSFER_STAGE_SETUP) { if (stage == USB_TRANSFER_STAGE_SETUP) {
addr = (endpoint->setup.value << 16) | endpoint->setup.index; addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length; len = endpoint->setup.length;
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES) if ((len > spi_flash.page_len) || (addr > spi_flash.num_bytes)
|| ((addr + len) > W25Q80BV_NUM_BYTES)) { || ((addr + len) > spi_flash.num_bytes)) {
return USB_REQUEST_STATUS_STALL; return USB_REQUEST_STATUS_STALL;
} else { } else {
usb_transfer_schedule_block(endpoint->out, &spiflash_buffer[0], len, usb_transfer_schedule_block(endpoint->out, &spiflash_buffer[0], len,
NULL, NULL); NULL, NULL);
spi_bus_start(spi_flash.bus, &ssp_config_w25q80bv);
w25q80bv_setup(&spi_flash);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
} }
} else if (stage == USB_TRANSFER_STAGE_DATA) { } else if (stage == USB_TRANSFER_STAGE_DATA) {
addr = (endpoint->setup.value << 16) | endpoint->setup.index; addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length; len = endpoint->setup.length;
/* This check is redundant but makes me feel better. */ /* This check is redundant but makes me feel better. */
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES) if ((len > spi_flash.page_len) || (addr > spi_flash.num_bytes)
|| ((addr + len) > W25Q80BV_NUM_BYTES)) { || ((addr + len) > spi_flash.num_bytes)) {
return USB_REQUEST_STATUS_STALL; return USB_REQUEST_STATUS_STALL;
} else { } else {
w25q80bv_program(addr, len, &spiflash_buffer[0]); w25q80bv_program(&spi_flash, addr, len, &spiflash_buffer[0]);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
} }
@ -85,8 +92,8 @@ usb_request_status_t usb_vendor_request_read_spiflash(
{ {
addr = (endpoint->setup.value << 16) | endpoint->setup.index; addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length; len = endpoint->setup.length;
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES) if ((len > spi_flash.page_len) || (addr > spi_flash.num_bytes)
|| ((addr + len) > W25Q80BV_NUM_BYTES)) { || ((addr + len) > spi_flash.num_bytes)) {
return USB_REQUEST_STATUS_STALL; return USB_REQUEST_STATUS_STALL;
} else { } else {
w25q80bv_read(addr, len, &spiflash_buffer[0]); w25q80bv_read(addr, len, &spiflash_buffer[0]);
@ -99,8 +106,8 @@ usb_request_status_t usb_vendor_request_read_spiflash(
addr = (endpoint->setup.value << 16) | endpoint->setup.index; addr = (endpoint->setup.value << 16) | endpoint->setup.index;
len = endpoint->setup.length; len = endpoint->setup.length;
/* This check is redundant but makes me feel better. */ /* This check is redundant but makes me feel better. */
if ((len > W25Q80BV_PAGE_LEN) || (addr > W25Q80BV_NUM_BYTES) if ((len > spi_flash.page_len) || (addr > spi_flash.num_bytes)
|| ((addr + len) > W25Q80BV_NUM_BYTES)) || ((addr + len) > spi_flash.num_bytes))
{ {
return USB_REQUEST_STATUS_STALL; return USB_REQUEST_STATUS_STALL;
} else } else

View File

@ -22,8 +22,6 @@
#include "usb_api_transceiver.h" #include "usb_api_transceiver.h"
#include <libopencm3/lpc43xx/gpio.h>
#include <max2837.h> #include <max2837.h>
#include <rf_path.h> #include <rf_path.h>
#include <tuning.h> #include <tuning.h>
@ -125,11 +123,11 @@ usb_request_status_t usb_vendor_request_set_amp_enable(
if (stage == USB_TRANSFER_STAGE_SETUP) { if (stage == USB_TRANSFER_STAGE_SETUP) {
switch (endpoint->setup.value) { switch (endpoint->setup.value) {
case 0: case 0:
rf_path_set_lna(0); rf_path_set_lna(&rf_path, 0);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
case 1: case 1:
rf_path_set_lna(1); rf_path_set_lna(&rf_path, 1);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
default: default:
@ -145,7 +143,7 @@ usb_request_status_t usb_vendor_request_set_lna_gain(
const usb_transfer_stage_t stage) const usb_transfer_stage_t stage)
{ {
if( stage == USB_TRANSFER_STAGE_SETUP ) { if( stage == USB_TRANSFER_STAGE_SETUP ) {
const uint8_t value = max2837_set_lna_gain(endpoint->setup.index); const uint8_t value = max2837_set_lna_gain(&max2837, endpoint->setup.index);
endpoint->buffer[0] = value; endpoint->buffer[0] = value;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL); NULL, NULL);
@ -159,7 +157,7 @@ usb_request_status_t usb_vendor_request_set_vga_gain(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{ {
if( stage == USB_TRANSFER_STAGE_SETUP ) { if( stage == USB_TRANSFER_STAGE_SETUP ) {
const uint8_t value = max2837_set_vga_gain(endpoint->setup.index); const uint8_t value = max2837_set_vga_gain(&max2837, endpoint->setup.index);
endpoint->buffer[0] = value; endpoint->buffer[0] = value;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL); NULL, NULL);
@ -173,7 +171,7 @@ usb_request_status_t usb_vendor_request_set_txvga_gain(
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
{ {
if( stage == USB_TRANSFER_STAGE_SETUP ) { if( stage == USB_TRANSFER_STAGE_SETUP ) {
const uint8_t value = max2837_set_txvga_gain(endpoint->setup.index); const uint8_t value = max2837_set_txvga_gain(&max2837, endpoint->setup.index);
endpoint->buffer[0] = value; endpoint->buffer[0] = value;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1, usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL); NULL, NULL);
@ -189,11 +187,11 @@ usb_request_status_t usb_vendor_request_set_antenna_enable(
if (stage == USB_TRANSFER_STAGE_SETUP) { if (stage == USB_TRANSFER_STAGE_SETUP) {
switch (endpoint->setup.value) { switch (endpoint->setup.value) {
case 0: case 0:
rf_path_set_antenna(0); rf_path_set_antenna(&rf_path, 0);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
case 1: case 1:
rf_path_set_antenna(1); rf_path_set_antenna(&rf_path, 1);
usb_transfer_schedule_ack(endpoint->in); usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
default: default:

View File

@ -19,14 +19,7 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/ssp.h>
#include "hackrf_core.h" #include "hackrf_core.h"
#include "max2837.h"
#include "rffc5071.h"
int main(void) int main(void)
{ {
@ -38,21 +31,20 @@ int main(void)
enable_rf_power(); enable_rf_power();
#endif #endif
cpu_clock_init(); cpu_clock_init();
ssp1_init();
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LED1 on */ led_on(LED1);
ssp1_set_mode_max2837(); ssp1_set_mode_max2837();
max2837_setup(); max2837_setup(&max2837);
rffc5071_setup(); rffc5071_setup(&rffc5072);
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */ led_on(LED2);
max2837_set_frequency(freq); max2837_set_frequency(&max2837, freq);
max2837_start(); max2837_start(&max2837);
max2837_tx(); max2837_tx(&max2837);
gpio_set(PORT_LED1_3, (PIN_LED3)); /* LED3 on */ led_on(LED3);
while (1); while (1);
max2837_stop(); max2837_stop(&max2837);
return 0; return 0;
} }

View File

@ -20,17 +20,14 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/sgpio.h> #include <libopencm3/lpc43xx/sgpio.h>
#include <hackrf_core.h> #include <hackrf_core.h>
#include <rf_path.h>
#include <sgpio.h>
#include <tuning.h> #include <tuning.h>
void tx_test() { void tx_test() {
sgpio_set_slice_mode(false); sgpio_set_slice_mode(&sgpio_config, false);
sgpio_configure(TRANSCEIVER_MODE_TX); sgpio_configure(&sgpio_config, TRANSCEIVER_MODE_TX);
// LSB goes out first, samples are 0x<Q1><I1><Q0><I0> // LSB goes out first, samples are 0x<Q1><I1><Q0><I0>
volatile uint32_t buffer[] = { volatile uint32_t buffer[] = {
@ -41,7 +38,7 @@ void tx_test() {
}; };
uint32_t i = 0; uint32_t i = 0;
sgpio_cpld_stream_enable(); sgpio_cpld_stream_enable(&sgpio_config);
while(true) { while(true) {
while(SGPIO_STATUS_1 == 0); while(SGPIO_STATUS_1 == 0);
@ -51,20 +48,20 @@ void tx_test() {
} }
void rx_test() { void rx_test() {
sgpio_set_slice_mode(false); sgpio_set_slice_mode(&sgpio_config, false);
sgpio_configure(TRANSCEIVER_MODE_RX); sgpio_configure(&sgpio_config, TRANSCEIVER_MODE_RX);
volatile uint32_t buffer[4096]; volatile uint32_t buffer[4096];
uint32_t i = 0; uint32_t i = 0;
int16_t magsq; int16_t magsq;
int8_t sigi, sigq; int8_t sigi, sigq;
sgpio_cpld_stream_enable(); sgpio_cpld_stream_enable(&sgpio_config);
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */ led_on(LED2);
while(true) { while(true) {
while(SGPIO_STATUS_1 == 0); while(SGPIO_STATUS_1 == 0);
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LED1 on */ led_on(LED1);
SGPIO_CLR_STATUS_1 = 1; SGPIO_CLR_STATUS_1 = 1;
buffer[i & 4095] = SGPIO_REG_SS(SGPIO_SLICE_A); buffer[i & 4095] = SGPIO_REG_SS(SGPIO_SLICE_A);
@ -79,9 +76,9 @@ void rx_test() {
/* illuminate LED3 only when magsq exceeds threshold */ /* illuminate LED3 only when magsq exceeds threshold */
if (magsq > 0x3c00) if (magsq > 0x3c00)
gpio_set(PORT_LED1_3, (PIN_LED3)); /* LED3 on */ led_on(LED3);
else else
gpio_clear(PORT_LED1_3, (PIN_LED3)); /* LED3 off */ led_off(LED3);
i++; i++;
} }
} }
@ -96,14 +93,13 @@ int main(void) {
enable_rf_power(); enable_rf_power();
#endif #endif
cpu_clock_init(); cpu_clock_init();
ssp1_init(); rf_path_init(&rf_path);
rf_path_init(); rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX);
rf_path_set_direction(RF_PATH_DIRECTION_RX);
set_freq(freq); set_freq(freq);
rx_test(); rx_test();
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */ led_on(LED2);
while (1) { while (1) {

View File

@ -19,22 +19,15 @@
* the Free Software Foundation, Inc., 51 Franklin Street, * the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/sgpio.h> #include <libopencm3/lpc43xx/sgpio.h>
#include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/cm3/scs.h>
#include <hackrf_core.h> #include <hackrf_core.h>
#include <max5864.h>
#include <sgpio.h>
volatile uint32_t buffer[4096]; volatile uint32_t buffer[4096];
void tx_test() { void tx_test() {
sgpio_set_slice_mode(false); sgpio_set_slice_mode(&sgpio_config, false);
sgpio_configure(TRANSCEIVER_MODE_TX); sgpio_configure(&sgpio_config, TRANSCEIVER_MODE_TX);
// LSB goes out first, samples are 0x<Q1><I1><Q0><I0> // LSB goes out first, samples are 0x<Q1><I1><Q0><I0>
buffer[0] = 0xda808080; buffer[0] = 0xda808080;
@ -44,7 +37,7 @@ void tx_test() {
uint32_t i = 0; uint32_t i = 0;
sgpio_cpld_stream_enable(); sgpio_cpld_stream_enable(&sgpio_config);
while(true) { while(true) {
while(SGPIO_STATUS_1 == 0); while(SGPIO_STATUS_1 == 0);
@ -54,12 +47,12 @@ void tx_test() {
} }
void rx_test() { void rx_test() {
sgpio_set_slice_mode(false); sgpio_set_slice_mode(&sgpio_config, false);
sgpio_configure(TRANSCEIVER_MODE_RX); sgpio_configure(&sgpio_config, TRANSCEIVER_MODE_RX);
uint32_t i = 0; uint32_t i = 0;
sgpio_cpld_stream_enable(); sgpio_cpld_stream_enable(&sgpio_config);
while(true) { while(true) {
while(SGPIO_STATUS_1 == 0); while(SGPIO_STATUS_1 == 0);
@ -72,12 +65,12 @@ int main(void) {
pin_setup(); pin_setup();
enable_1v8_power(); enable_1v8_power();
cpu_clock_init(); cpu_clock_init();
ssp1_init();
gpio_set(PORT_LED1_3, PIN_LED1); led_on(LED1);
ssp1_set_mode_max5864(); ssp1_set_mode_max5864();
max5864_xcvr(); max5864_setup(&max5864);
max5864_xcvr(&max5864);
while (1) { while (1) {

View File

@ -21,11 +21,8 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h> #include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/sgpio.h> #include <libopencm3/lpc43xx/sgpio.h>
#include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/cm3/scs.h>
#include <hackrf_core.h> #include <hackrf_core.h>
@ -353,8 +350,7 @@ int main(void)
pin_setup(); pin_setup();
enable_1v8_power(); enable_1v8_power();
cpu_clock_init(); cpu_clock_init();
ssp1_init(); led_on(LED1);
gpio_set(PORT_LED1_3, PIN_LED1);
//test_sgpio_sliceA_D(); //test_sgpio_sliceA_D();
test_sgpio_interface(); test_sgpio_interface();

View File

@ -19,13 +19,7 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/ssp.h>
#include "hackrf_core.h" #include "hackrf_core.h"
#include "max2837.h"
int main(void) int main(void)
{ {
@ -37,19 +31,18 @@ int main(void)
enable_rf_power(); enable_rf_power();
#endif #endif
cpu_clock_init(); cpu_clock_init();
ssp1_init();
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LED1 on */ led_on(LED1);
ssp1_set_mode_max2837(); ssp1_set_mode_max2837();
max2837_setup(); max2837_setup(&max2837);
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */ led_on(LED2);
max2837_set_frequency(freq); max2837_set_frequency(&max2837, freq);
max2837_start(); max2837_start(&max2837);
max2837_tx(); max2837_tx(&max2837);
gpio_set(PORT_LED1_3, (PIN_LED3)); /* LED3 on */ led_on(LED3);
while (1); while (1);
max2837_stop(); max2837_stop(&max2837);
return 0; return 0;
} }

View File

@ -19,11 +19,7 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h" #include "hackrf_core.h"
#include "w25q80bv.h"
int main(void) int main(void)
{ {
@ -39,17 +35,19 @@ int main(void)
/* program test data to SPI flash */ /* program test data to SPI flash */
for (i = 0; i < 515; i++) for (i = 0; i < 515; i++)
buf[i] = (i * 3) & 0xFF; buf[i] = (i * 3) & 0xFF;
w25q80bv_setup(); w25q80bv_setup(&w25q80bv);
w25q80bv_chip_erase(); w25q80bv_chip_erase(&w25q80bv);
w25q80bv_program(790, 515, &buf[0]); w25q80bv_program(&w25q80bv, 790, 515, &buf[0]);
/* blink LED1 and LED3 */ /* blink LED1 and LED3 */
while (1) while (1)
{ {
gpio_set(PORT_LED1_3, (PIN_LED1|PIN_LED3)); /* LEDs on */ led_on(LED1);
led_on(LED3);
for (i = 0; i < 8000000; i++) /* Wait a bit. */ for (i = 0; i < 8000000; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
gpio_clear(PORT_LED1_3, (PIN_LED1|PIN_LED3)); /* LED off */ led_off(LED1);
led_off(LED3);
for (i = 0; i < 8000000; i++) /* Wait a bit. */ for (i = 0; i < 8000000; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
} }

View File

@ -19,10 +19,6 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/i2c.h>
#include "hackrf_core.h" #include "hackrf_core.h"
int main(void) int main(void)
@ -35,23 +31,27 @@ int main(void)
cpu_clock_init(); cpu_clock_init();
gpio_set(PORT_LED1_3, (PIN_LED1|PIN_LED2|PIN_LED3)); /* LEDs on */ led_on(LED1);
led_on(LED2);
led_on(LED3);
while (1) while (1)
{ {
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LEDs on */ led_on(LED1);
for (i = 0; i < 2000000; i++) /* Wait a bit. */ for (i = 0; i < 2000000; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
gpio_set(PORT_LED1_3, (PIN_LED1|PIN_LED2)); /* LEDs on */ led_on(LED2);
for (i = 0; i < 2000000; i++) /* Wait a bit. */ for (i = 0; i < 2000000; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
gpio_set(PORT_LED1_3, (PIN_LED1|PIN_LED2|PIN_LED3)); /* LED off */ led_on(LED3);
for (i = 0; i < 2000000; i++) /* Wait a bit. */ for (i = 0; i < 2000000; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
gpio_clear(PORT_LED1_3, (PIN_LED1|PIN_LED2|PIN_LED3)); /* LED off */ led_off(LED1);
led_off(LED2);
led_off(LED3);
for (i = 0; i < 2000000; i++) /* Wait a bit. */ for (i = 0; i < 2000000; i++) /* Wait a bit. */
__asm__("nop"); __asm__("nop");
} }

View File

@ -19,9 +19,6 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/m4/nvic.h> #include <libopencm3/lpc43xx/m4/nvic.h>
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scs.h> #include <libopencm3/cm3/scs.h>
@ -139,19 +136,21 @@ int main(void)
systick_setup(); systick_setup();
gpio_set(PORT_LED1_3, (PIN_LED1|PIN_LED2|PIN_LED3)); /* LEDs on */ led_on(LED1);
led_on(LED2);
led_on(LED3);
while (1) while (1)
{ {
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LED1 on */ led_on(LED1);
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */ led_on(LED2);
gpio_set(PORT_LED1_3, (PIN_LED3)); /* LED3 on */ led_on(LED3);
sys_tick_wait_time_ms(500); sys_tick_wait_time_ms(500);
gpio_clear(PORT_LED1_3, (PIN_LED3)); /* LED3 off */ led_off(LED1);
gpio_clear(PORT_LED1_3, (PIN_LED2)); /* LED2 off */ led_off(LED2);
gpio_clear(PORT_LED1_3, (PIN_LED1)); /* LED1 off */ led_off(LED3);
sys_tick_wait_time_ms(500); sys_tick_wait_time_ms(500);
} }

View File

@ -19,9 +19,6 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/m4/nvic.h> #include <libopencm3/lpc43xx/m4/nvic.h>
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scs.h> #include <libopencm3/cm3/scs.h>

View File

@ -19,9 +19,6 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/m4/nvic.h> #include <libopencm3/lpc43xx/m4/nvic.h>
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scs.h> #include <libopencm3/cm3/scs.h>
@ -138,7 +135,7 @@ extern uint32_t test_nb_instruction_per_sec_150_nop_asm();
extern uint32_t test_nb_instruction_per_sec_200_nop_asm(); extern uint32_t test_nb_instruction_per_sec_200_nop_asm();
extern uint32_t test_nb_instruction_per_sec_1000_nop_asm(); extern uint32_t test_nb_instruction_per_sec_1000_nop_asm();
#define LED1_TOGGLE() (gpio_toggle(PORT_LED1_3, (PIN_LED1))) #define LED1_TOGGLE() (led_toggle(LED1))
int main(void) int main(void)
{ {
@ -152,7 +149,7 @@ int main(void)
systick_setup(); systick_setup();
gpio_clear(PORT_LED1_3, (PIN_LED1)); /* LED1 off */ led_off(LED1);
/* Test number of instruction per second (MIPS) slow blink ON 1s, OFF 1s */ /* Test number of instruction per second (MIPS) slow blink ON 1s, OFF 1s */
LED1_TOGGLE(); LED1_TOGGLE();
@ -192,15 +189,15 @@ LED1_TOGGLE();
/* Test finished fast blink */ /* Test finished fast blink */
while (1) while (1)
{ {
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LED1 on */ led_on(LED1);
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */ led_on(LED2);
gpio_set(PORT_LED1_3, (PIN_LED3)); /* LED3 on */ led_on(LED3);
sys_tick_wait_time_ms(250); sys_tick_wait_time_ms(250);
gpio_clear(PORT_LED1_3, (PIN_LED3)); /* LED3 off */ led_off(LED1);
gpio_clear(PORT_LED1_3, (PIN_LED2)); /* LED2 off */ led_off(LED2);
gpio_clear(PORT_LED1_3, (PIN_LED1)); /* LED1 off */ led_off(LED3);
sys_tick_wait_time_ms(250); sys_tick_wait_time_ms(250);
} }