Merge pull request #233 from mossmann/jboone-abstract_buses

Abstract buses
This commit is contained in:
Dominic Spill
2016-01-13 20:45:28 +00:00
66 changed files with 2625 additions and 1744 deletions

View File

@ -19,13 +19,8 @@
* Boston, MA 02110-1301, USA.
*/
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h"
uint32_t boot0, boot1, boot2, boot3;
int main(void)
{
int i;
@ -34,18 +29,20 @@ int main(void)
/* enable all power supplies */
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)
{
boot0 = BOOT0_STATE;
boot1 = BOOT1_STATE;
boot2 = BOOT2_STATE;
boot3 = BOOT3_STATE;
led_on(LED1);
led_on(LED2);
led_on(LED3);
gpio_set(PORT_LED1_3, (PIN_LED1|PIN_LED2|PIN_LED3)); /* LEDs on */
for (i = 0; i < 2000000; i++) /* Wait a bit. */
__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. */
__asm__("nop");
}

View File

@ -22,7 +22,6 @@
#include "cpld_jtag.h"
#include "hackrf_core.h"
#include "xapp058/micro.h"
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <stdint.h>
@ -30,47 +29,45 @@ static refill_buffer_cb refill_buffer;
static uint32_t xsvf_buffer_len, xsvf_pos;
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_TCK, 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);
/* TDO is an input */
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO;
/* the rest are outputs */
GPIO_DIR(PORT_CPLD_TCK) |= PIN_CPLD_TCK;
GPIO_DIR(PORT_CPLD_TMS) |= PIN_CPLD_TMS;
GPIO_DIR(PORT_CPLD_TDI) |= PIN_CPLD_TDI;
gpio_input(jtag->gpio->gpio_tdo);
gpio_output(jtag->gpio->gpio_tck);
gpio_output(jtag->gpio->gpio_tms);
gpio_output(jtag->gpio->gpio_tdi);
}
/* 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_TCK, 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);
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO;
GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK;
GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS;
GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI;
gpio_input(jtag->gpio->gpio_tdo);
gpio_input(jtag->gpio->gpio_tck);
gpio_input(jtag->gpio->gpio_tms);
gpio_input(jtag->gpio->gpio_tdi);
}
/* return 0 if success else return error code see xsvfExecute() */
int cpld_jtag_program(
jtag_t* const jtag,
const uint32_t buffer_length,
unsigned char* const buffer,
refill_buffer_cb refill
) {
int error;
cpld_jtag_setup();
cpld_jtag_setup(jtag);
xsvf_buffer = buffer;
xsvf_buffer_len = buffer_length;
refill_buffer = refill;
error = xsvfExecute();
cpld_jtag_release();
error = xsvfExecute(jtag->gpio);
cpld_jtag_release(jtag);
return error;
}

View File

@ -24,9 +24,22 @@
#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);
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.
*
@ -34,6 +47,7 @@ void cpld_jtag_release(void);
* contents of the buffer has been streamed to the CPLD the given
* refill_buffer callback will be called. */
int cpld_jtag_program(
jtag_t* const jtag,
const uint32_t buffer_length,
unsigned char* const buffer,
refill_buffer_cb refill

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 "si5351c.h"
#include "spi_ssp.h"
#include "max2837.h"
#include "max2837_target.h"
#include "max5864.h"
#include "max5864_target.h"
#include "rffc5071.h"
#include "sgpio.h"
#include "rf_path.h"
#include <libopencm3/lpc43xx/i2c.h>
#include "rffc5071_spi.h"
#include "w25q80bv.h"
#include "w25q80bv_target.h"
#include "i2c_bus.h"
#include "i2c_lpc.h"
#include <libopencm3/lpc43xx/cgu.h>
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.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)
/* 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)
{
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 ? */
if (a & 0x1 || b)
si5351c_set_int_mode(0, 0);
si5351c_set_int_mode(&clock_gen, 0, 0);
else
si5351c_set_int_mode(0, 1);
si5351c_set_int_mode(&clock_gen, 0, 1);
/* Final MS values */
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;
/* 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). */
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) */
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;
}
@ -174,13 +451,13 @@ bool sample_rate_set(const uint32_t sample_rate_hz) {
* values are irrelevant. */
/* 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). */
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. */
si5351c_configure_multisynth(3, 4608, 0, 1, r_div_sgpio);
si5351c_configure_multisynth(&clock_gen, 3, 4608, 0, 1, r_div_sgpio);
return true;
#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). */
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). */
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) */
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;
#endif
}
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
@ -264,15 +541,15 @@ void cpu_clock_init(void)
/* use IRC as clock source for APB3 */
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_oeb_pin_control();
si5351c_power_down_all_clocks();
si5351c_set_crystal_configuration();
si5351c_enable_xo_and_ms_fanout();
si5351c_configure_pll_sources();
si5351c_configure_pll_multisynth();
si5351c_disable_all_outputs(&clock_gen);
si5351c_disable_oeb_pin_control(&clock_gen);
si5351c_power_down_all_clocks(&clock_gen);
si5351c_set_crystal_configuration(&clock_gen);
si5351c_enable_xo_and_ms_fanout(&clock_gen);
si5351c_configure_pll_sources(&clock_gen);
si5351c_configure_pll_multisynth(&clock_gen);
#ifdef JELLYBEAN
/*
@ -288,13 +565,13 @@ void cpu_clock_init(void)
*/
/* 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. */
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. */
si5351c_configure_multisynth(5, 1536, 0, 1, 0); /* 50MHz */
si5351c_configure_multisynth(&clock_gen, 5, 1536, 0, 1, 0); /* 50MHz */
#endif
#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. */
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. */
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. */
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. */
/* MS7/CLK7 is the source for the LPC43xx microcontroller. */
uint8_t ms7data[] = { 90, 255, 20, 0 };
si5351c_write(ms7data, sizeof(ms7data));
si5351c_write(&clock_gen, ms7data, sizeof(ms7data));
#endif
/* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */
sample_rate_set(10000000);
si5351c_set_clock_source(PLL_SOURCE_XTAL);
si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL);
// soft reset
uint8_t resetdata[] = { 177, 0xac };
si5351c_write(resetdata, sizeof(resetdata));
si5351c_enable_clock_outputs();
si5351c_write(&clock_gen, resetdata, sizeof(resetdata));
si5351c_enable_clock_outputs(&clock_gen);
//FIXME disable I2C
/* 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
@ -411,6 +688,12 @@ void cpu_clock_init(void)
/* Switch APB3 clock over to use PLL1 (204MHz) */
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_AUTOBLOCK(1)
| CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1);
CGU_BASE_SSP0_CLK = CGU_BASE_SSP0_CLK_AUTOBLOCK(1)
| CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1);
CGU_BASE_SSP1_CLK = CGU_BASE_SSP1_CLK_AUTOBLOCK(1)
| CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1);
}
@ -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)
{
/* 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
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);
spi_bus_start(max2837.bus, &ssp_config_max2837);
}
void ssp1_set_mode_max5864(void)
{
/* 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
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);
spi_bus_start(max5864.bus, &ssp_config_max5864);
}
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_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0);
GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO;
GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK;
GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS;
GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI;
gpio_input(&gpio_cpld_tdo);
gpio_input(&gpio_cpld_tck);
gpio_input(&gpio_cpld_tms);
gpio_input(&gpio_cpld_tdi);
/* Configure SCU Pin Mux as GPIO */
scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_NOPULL);
@ -596,49 +823,62 @@ void pin_setup(void) {
#endif
/* Configure all GPIO as Input (safe state) */
GPIO0_DIR = 0;
GPIO1_DIR = 0;
GPIO2_DIR = 0;
GPIO3_DIR = 0;
GPIO4_DIR = 0;
GPIO5_DIR = 0;
GPIO6_DIR = 0;
GPIO7_DIR = 0;
gpio_init();
/* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */
GPIO2_DIR |= (PIN_LED1 | PIN_LED2 | PIN_LED3);
gpio_output(&gpio_led[0]);
gpio_output(&gpio_led[1]);
gpio_output(&gpio_led[2]);
/* GPIO3[6] on P6_10 as output. */
GPIO3_DIR |= PIN_EN1V8;
gpio_output(&gpio_1v8_enable);
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) */
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_SSP1_SSEL, (SCU_SSP_IO | SCU_CONF_FUNCTION1));
/* Safe state: start with VAA turned off: */
disable_rf_power();
#endif
/* 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 */
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) {
gpio_set(PORT_EN1V8, PIN_EN1V8);
gpio_set(&gpio_1v8_enable);
}
void disable_1v8_power(void) {
gpio_clear(PORT_EN1V8, PIN_EN1V8);
gpio_clear(&gpio_1v8_enable);
}
#ifdef HACKRF_ONE
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) {
gpio_set(PORT_NO_VAA_ENABLE, PIN_NO_VAA_ENABLE);
gpio_set(&gpio_vaa_disable);
}
#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 <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 */
#define BOARD_ID_JELLYBEAN 0
#define BOARD_ID_JAWBREAKER 1
@ -206,142 +217,6 @@ extern "C"
#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 {
TRANSCEIVER_MODE_OFF = 0,
TRANSCEIVER_MODE_RX = 1,
@ -352,10 +227,23 @@ typedef enum {
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_pll1_low_speed(void);
void cpu_clock_pll1_max_speed(void);
void ssp1_init(void);
void ssp1_set_mode_max2837(void);
void ssp1_set_mode_max5864(void);
@ -373,6 +261,16 @@ void enable_rf_power(void);
void disable_rf_power(void);
#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
}
#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
* program would do if it had a real spi library
@ -11,19 +33,8 @@
#include "max2837.h"
#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. */
static uint16_t max2837_regs_default[MAX2837_NUM_REGS] = {
static const uint16_t max2837_regs_default[MAX2837_NUM_REGS] = {
0x150, /* 0 */
0x002, /* 1 */
0x1f4, /* 2 */
@ -62,283 +73,130 @@ static uint16_t max2837_regs_default[MAX2837_NUM_REGS] = {
0x080, /* 30 */
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. */
void max2837_init(void)
static void max2837_init(max2837_driver_t* const drv)
{
LOG("# max2837_init\n");
memcpy(max2837_regs, max2837_regs_default, sizeof(max2837_regs));
max2837_regs_dirty = 0xffffffff;
drv->target_init(drv);
max2837_set_mode(drv, MAX2837_MODE_SHUTDOWN);
memcpy(drv->regs, max2837_regs_default, sizeof(drv->regs));
drv->regs_dirty = 0xffffffff;
/* Write default register values to chip. */
max2837_regs_commit();
max2837_regs_commit(drv);
}
/*
* Set up pins for GPIO and SPI control, configure SSP peripheral for SPI, and
* set our own default register configuration.
*/
void max2837_setup(void)
void max2837_setup(max2837_driver_t* const drv)
{
LOG("# max2837_setup\n");
#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");
max2837_init(drv);
/* Use SPI control instead of B1-B7 pins for gain settings. */
set_MAX2837_TXVGA_GAIN_SPI_EN(1);
set_MAX2837_TXVGA_GAIN_MSB_SPI_EN(1);
set_MAX2837_TXVGA_GAIN_SPI_EN(drv, 1);
set_MAX2837_TXVGA_GAIN_MSB_SPI_EN(drv, 1);
//set_MAX2837_TXVGA_GAIN(0x3f); /* maximum attenuation */
set_MAX2837_TXVGA_GAIN(0x00); /* minimum attenuation */
set_MAX2837_VGAMUX_enable(1);
set_MAX2837_VGA_EN(1);
set_MAX2837_HPC_RXGAIN_EN(0);
set_MAX2837_HPC_STOP(MAX2837_STOP_1K);
set_MAX2837_LNAgain_SPI_EN(1);
set_MAX2837_LNAgain(MAX2837_LNAgain_MAX); /* maximum gain */
set_MAX2837_VGAgain_SPI_EN(1);
set_MAX2837_VGA(0x18); /* reasonable gain for noisy 2.4GHz environment */
set_MAX2837_TXVGA_GAIN(drv, 0x00); /* minimum attenuation */
set_MAX2837_VGAMUX_enable(drv, 1);
set_MAX2837_VGA_EN(drv, 1);
set_MAX2837_HPC_RXGAIN_EN(drv, 0);
set_MAX2837_HPC_STOP(drv, MAX2837_STOP_1K);
set_MAX2837_LNAgain_SPI_EN(drv, 1);
set_MAX2837_LNAgain(drv, MAX2837_LNAgain_MAX); /* maximum gain */
set_MAX2837_VGAgain_SPI_EN(drv, 1);
set_MAX2837_VGA(drv, 0x18); /* reasonable gain for noisy 2.4GHz environment */
/* maximum rx output common-mode voltage */
set_MAX2837_BUFF_VCM(MAX2837_BUFF_VCM_1_25);
set_MAX2837_BUFF_VCM(drv, MAX2837_BUFF_VCM_1_25);
/* configure baseband filter for 8 MHz TX */
set_MAX2837_LPF_EN(1);
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_RxLPF);
set_MAX2837_FT(MAX2837_FT_5M);
set_MAX2837_LPF_EN(drv, 1);
set_MAX2837_ModeCtrl(drv, MAX2837_ModeCtrl_RxLPF);
set_MAX2837_FT(drv, MAX2837_FT_5M);
max2837_regs_commit();
max2837_regs_commit(drv);
}
/* SPI register read. */
uint16_t max2837_spi_read(uint8_t r) {
gpio_clear(PORT_XCVR_CS, PIN_XCVR_CS);
const uint16_t value = ssp_transfer(SSP1_NUM, (uint16_t)((1 << 15) | (r << 10)));
gpio_set(PORT_XCVR_CS, PIN_XCVR_CS);
static uint16_t max2837_read(max2837_driver_t* const drv, uint8_t r) {
uint16_t value = (1 << 15) | (r << 10);
spi_bus_transfer(drv->bus, &value, 1);
return value & 0x3ff;
}
/* SPI register write */
void max2837_spi_write(uint8_t r, uint16_t v) {
#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
static void max2837_write(max2837_driver_t* const drv, uint8_t r, uint16_t v) {
uint16_t value = (r << 10) | (v & 0x3ff);
spi_bus_transfer(drv->bus, &value, 1);
}
uint16_t max2837_reg_read(uint8_t r)
uint16_t max2837_reg_read(max2837_driver_t* const drv, uint8_t r)
{
if ((max2837_regs_dirty >> r) & 0x1) {
max2837_regs[r] = max2837_spi_read(r);
if ((drv->regs_dirty >> r) & 0x1) {
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;
max2837_spi_write(r, v);
MAX2837_REG_SET_CLEAN(r);
drv->regs[r] = v;
max2837_write(drv, r, v);
MAX2837_REG_SET_CLEAN(drv, r);
}
/* This functions should not be needed, and might be confusing. DELETE. */
void max2837_regs_read(void)
static inline void max2837_reg_commit(max2837_driver_t* const drv, uint8_t r)
{
;
max2837_reg_write(drv, r, drv->regs[r]);
}
static inline void max2837_reg_commit(uint8_t r)
{
max2837_reg_write(r,max2837_regs[r]);
}
void max2837_regs_commit(void)
void max2837_regs_commit(max2837_driver_t* const drv)
{
int r;
for(r = 0; r < MAX2837_NUM_REGS; r++) {
if ((max2837_regs_dirty >> r) & 0x1) {
max2837_reg_commit(r);
if ((drv->regs_dirty >> r) & 0x1) {
max2837_reg_commit(drv, r);
}
}
}
void max2837_mode_shutdown(void) {
/* All circuit blocks are powered down, except the 4-wire serial bus
* and its internal programmable registers.
*/
gpio_clear(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
void max2837_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode) {
drv->set_mode(drv, new_mode);
}
void max2837_mode_standby(void) {
/* Used to enable the frequency synthesizer block while the rest of the
* device is powered down. In this mode, PLL, VCO, and LO generator
* are on, so that Tx or Rx modes can be quickly enabled from this mode.
* These and other blocks can be selectively enabled in this mode.
*/
gpio_clear(PORT_XCVR_ENABLE, (PIN_XCVR_RXENABLE | PIN_XCVR_TXENABLE));
gpio_set(PORT_XCVR_ENABLE, PIN_XCVR_ENABLE);
max2837_mode_t max2837_mode(max2837_driver_t* const drv) {
return drv->mode;
}
void max2837_mode_tx(void) {
/* All Tx circuit blocks are powered on. The external PA is powered on
* after a programmable delay using the on-chip PA bias DAC. The slow-
* charging Rx circuits are in a precharged idle-off state for fast
* Tx-to-Rx turnaround time.
*/
gpio_clear(PORT_XCVR_ENABLE, PIN_XCVR_RXENABLE);
gpio_set(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_TXENABLE));
}
void max2837_mode_rx(void) {
/* All Rx circuit blocks are powered on and active. Antenna signal is
* applied; RF is downconverted, filtered, and buffered at Rx BB I and Q
* outputs. The slow- charging Tx circuits are in a precharged idle-off
* state for fast Rx-to-Tx turnaround time.
*/
gpio_clear(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE);
gpio_set(PORT_XCVR_ENABLE,
(PIN_XCVR_ENABLE | PIN_XCVR_RXENABLE));
}
max2837_mode_t max2837_mode(void) {
if( gpio_get(PORT_XCVR_ENABLE, PIN_XCVR_ENABLE) ) {
if( gpio_get(PORT_XCVR_ENABLE, PIN_XCVR_TXENABLE) ) {
return MAX2837_MODE_TX;
} else if( gpio_get(PORT_XCVR_ENABLE, PIN_XCVR_RXENABLE) ) {
return MAX2837_MODE_RX;
} else {
return MAX2837_MODE_STANDBY;
}
} else {
return MAX2837_MODE_SHUTDOWN;
}
}
void max2837_set_mode(const max2837_mode_t new_mode) {
switch(new_mode) {
case MAX2837_MODE_SHUTDOWN:
max2837_mode_shutdown();
break;
case MAX2837_MODE_STANDBY:
max2837_mode_standby();
break;
case MAX2837_MODE_TX:
max2837_mode_tx();
break;
case MAX2837_MODE_RX:
max2837_mode_rx();
break;
default:
break;
}
}
void max2837_start(void)
void max2837_start(max2837_driver_t* const drv)
{
LOG("# max2837_start\n");
set_MAX2837_EN_SPI(1);
max2837_regs_commit();
#if !defined TEST
max2837_mode_standby();
#endif
set_MAX2837_EN_SPI(drv, 1);
max2837_regs_commit(drv);
max2837_set_mode(drv, MAX2837_MODE_STANDBY);
}
void max2837_tx(void)
void max2837_tx(max2837_driver_t* const drv)
{
LOG("# max2837_tx\n");
#if !defined TEST
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_TxLPF);
max2837_regs_commit();
max2837_mode_tx();
#endif
set_MAX2837_ModeCtrl(drv, MAX2837_ModeCtrl_TxLPF);
max2837_regs_commit(drv);
max2837_set_mode(drv, MAX2837_MODE_TX);
}
void max2837_rx(void)
void max2837_rx(max2837_driver_t* const drv)
{
LOG("# max2837_rx\n");
set_MAX2837_ModeCtrl(MAX2837_ModeCtrl_RxLPF);
max2837_regs_commit();
#if !defined TEST
max2837_mode_rx();
#endif
set_MAX2837_ModeCtrl(drv, MAX2837_ModeCtrl_RxLPF);
max2837_regs_commit(drv);
max2837_set_mode(drv, MAX2837_MODE_RX);
}
void max2837_stop(void)
void max2837_stop(max2837_driver_t* const drv)
{
LOG("# max2837_stop\n");
set_MAX2837_EN_SPI(0);
max2837_regs_commit();
#if !defined TEST
max2837_mode_shutdown();
#endif
set_MAX2837_EN_SPI(drv, 0);
max2837_regs_commit(drv);
max2837_set_mode(drv, MAX2837_MODE_SHUTDOWN);
}
void max2837_set_frequency(uint32_t freq)
void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq)
{
uint8_t band;
uint8_t lna_band;
@ -366,9 +224,6 @@ void max2837_set_frequency(uint32_t freq)
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 */
div_int = freq / 30000000;
div_rem = freq % 30000000;
@ -382,22 +237,21 @@ void max2837_set_frequency(uint32_t freq)
div_rem -= div_cmp;
}
}
LOG("# int %ld, frac %ld\n", div_int, div_frac);
/* Band settings */
set_MAX2837_LOGEN_BSW(band);
set_MAX2837_LNAband(lna_band);
set_MAX2837_LOGEN_BSW(drv, band);
set_MAX2837_LNAband(drv, lna_band);
/* Write order matters here, so commit INT and FRAC_HI before
* committing FRAC_LO, which is the trigger for VCO
* auto-select. TODO - it's cleaner this way, but it would be
* faster to explicitly commit the registers explicitly so the
* dirty bits aren't scanned twice. */
set_MAX2837_SYN_INT(div_int);
set_MAX2837_SYN_FRAC_HI((div_frac >> 10) & 0x3ff);
max2837_regs_commit();
set_MAX2837_SYN_FRAC_LO(div_frac & 0x3ff);
max2837_regs_commit();
set_MAX2837_SYN_INT(drv, div_int);
set_MAX2837_SYN_FRAC_HI(drv, (div_frac >> 10) & 0x3ff);
max2837_regs_commit(drv);
set_MAX2837_SYN_FRAC_LO(drv, div_frac & 0x3ff);
max2837_regs_commit(drv);
}
typedef struct {
@ -425,7 +279,7 @@ static const max2837_ft_t max2837_ft[] = {
{ 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;
while( p->bandwidth_hz != 0 ) {
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 ) {
set_MAX2837_FT(p->ft);
max2837_regs_commit();
set_MAX2837_FT(drv, p->ft);
max2837_regs_commit(drv);
return true;
} else {
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;
switch(gain_db){
case 40:
@ -467,21 +321,21 @@ bool max2837_set_lna_gain(const uint32_t gain_db) {
default:
return false;
}
set_MAX2837_LNAgain(val);
max2837_reg_commit(1);
set_MAX2837_LNAgain(drv, val);
max2837_reg_commit(drv, 1);
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 */
return false;
set_MAX2837_VGA( 31-(gain_db >> 1) );
max2837_reg_commit(5);
set_MAX2837_VGA(drv, 31-(gain_db >> 1) );
max2837_reg_commit(drv, 5);
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;
if(gain_db <16){
val = 31-gain_db;
@ -490,18 +344,7 @@ bool max2837_set_txvga_gain(const uint32_t gain_db) {
val = 31-(gain_db-16);
}
set_MAX2837_TXVGA_GAIN(val);
max2837_reg_commit(29);
set_MAX2837_TXVGA_GAIN(drv, val);
max2837_reg_commit(drv, 29);
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
#define __MAX2837_H
#include <stdint.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. */
#define MAX2837_NUM_REGS 32
#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 {
MAX2837_MODE_SHUTDOWN,
MAX2837_MODE_STANDBY,
@ -44,27 +40,63 @@ typedef enum {
MAX2837_MODE_RX
} max2837_mode_t;
void max2837_mode_shutdown(void);
void max2837_mode_standby(void);
void max2837_mode_tx(void);
void max2837_mode_rx(void);
struct max2837_driver_t;
typedef struct max2837_driver_t max2837_driver_t;
max2837_mode_t max2837_mode(void);
void max2837_set_mode(const max2837_mode_t new_mode);
struct max2837_driver_t {
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 */
extern void max2837_start(void);
extern void max2837_stop(void);
extern void max2837_start(max2837_driver_t* const drv);
extern void max2837_stop(max2837_driver_t* const drv);
/* Set frequency in Hz. Frequency setting is a multi-step function
* where order of register writes matters. */
extern void max2837_set_frequency(uint32_t freq);
bool max2837_set_lpf_bandwidth(const uint32_t bandwidth_hz);
bool max2837_set_lna_gain(const uint32_t gain_db);
bool max2837_set_vga_gain(const uint32_t gain_db);
bool max2837_set_txvga_gain(const uint32_t gain_db);
extern void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq);
bool max2837_set_lpf_bandwidth(max2837_driver_t* const drv, const uint32_t bandwidth_hz);
bool max2837_set_lna_gain(max2837_driver_t* const drv, const uint32_t gain_db);
bool max2837_set_vga_gain(max2837_driver_t* const drv, const uint32_t gain_db);
bool max2837_set_txvga_gain(max2837_driver_t* const drv, const uint32_t gain_db);
extern void max2837_tx(void);
extern void max2837_rx(void);
extern void max2837_tx(max2837_driver_t* const drv);
extern void max2837_rx(max2837_driver_t* const drv);
#endif // __MAX2837_H

View File

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

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 <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/ssp.h>
#include "hackrf_core.h"
#include "max5864.h"
void max5864_spi_write(uint_fast8_t value) {
gpio_clear(PORT_AD_CS, PIN_AD_CS);
ssp_transfer(SSP1_NUM, value);
gpio_set(PORT_AD_CS, PIN_AD_CS);
static void max5864_write(max5864_driver_t* const drv, uint8_t value) {
spi_bus_transfer(drv->bus, &value, 1);
}
static void max5864_init(max5864_driver_t* const drv) {
drv->target_init(drv);
}
void max5864_setup(max5864_driver_t* const drv) {
max5864_init(drv);
}
/* Set MAX5864 operation mode to "Shutdown":
@ -39,9 +41,9 @@ void max5864_spi_write(uint_fast8_t value) {
* ADCs: off (bus is tri-stated)
* 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":
@ -50,9 +52,9 @@ void max5864_shutdown()
* ADCs: off (bus is tri-stated)
* 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":
@ -61,9 +63,9 @@ void max5864_standby()
* ADCs: off (bus is tri-stated)
* 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":
@ -72,9 +74,9 @@ void max5864_idle()
* ADCs: on
* 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":
@ -83,9 +85,9 @@ void max5864_rx()
* ADCs: off (bus is tri-stated)
* 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":
@ -94,7 +96,7 @@ void max5864_tx()
* ADCs: 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
#define __MAX5864_H
void max5864_shutdown();
void max5864_standby();
void max5864_idle();
void max5864_rx();
void max5864_tx();
void max5864_xcvr();
#include "spi_bus.h"
struct max5864_driver_t;
typedef struct max5864_driver_t max5864_driver_t;
struct max5864_driver_t {
spi_bus_t* const bus;
void (*target_init)(max5864_driver_t* const drv);
};
void max5864_setup(max5864_driver_t* const drv);
void max5864_shutdown(max5864_driver_t* const drv);
void max5864_standby(max5864_driver_t* const drv);
void max5864_idle(max5864_driver_t* const drv);
void max5864_rx(max5864_driver_t* const drv);
void max5864_tx(max5864_driver_t* const drv);
void max5864_xcvr(max5864_driver_t* const drv);
#endif // __MAX5864_H

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of HackRF.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "max5864_target.h"
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h"
void max5864_target_init(max5864_driver_t* const drv) {
(void)drv;
/* Configure SSP1 Peripheral (to be moved later in SSP driver) */
scu_pinmux(SCU_SSP1_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 <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.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 */
#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) {
gpio_set(PORT_TX, PIN_TX);
gpio_clear(PORT_RX, PIN_RX);
gpio_set(rf_path->gpio_tx);
gpio_clear(rf_path->gpio_rx);
} else {
gpio_clear(PORT_TX, PIN_TX);
gpio_set(PORT_RX, PIN_RX);
gpio_clear(rf_path->gpio_tx);
gpio_set(rf_path->gpio_rx);
}
if (ctrl & SWITCHCTRL_MIX_BYPASS) {
gpio_set(PORT_MIX_BYPASS, PIN_MIX_BYPASS);
gpio_clear(PORT_NO_MIX_BYPASS, PIN_NO_MIX_BYPASS);
gpio_set(rf_path->gpio_mix_bypass);
gpio_clear(rf_path->gpio_no_mix_bypass);
if (ctrl & SWITCHCTRL_TX) {
gpio_set(PORT_TX_MIX_BP, PIN_TX_MIX_BP);
gpio_clear(PORT_RX_MIX_BP, PIN_RX_MIX_BP);
gpio_set(rf_path->gpio_tx_mix_bp);
gpio_clear(rf_path->gpio_rx_mix_bp);
} else {
gpio_clear(PORT_TX_MIX_BP, PIN_TX_MIX_BP);
gpio_set(PORT_RX_MIX_BP, PIN_RX_MIX_BP);
gpio_clear(rf_path->gpio_tx_mix_bp);
gpio_set(rf_path->gpio_rx_mix_bp);
}
} else {
gpio_clear(PORT_MIX_BYPASS, PIN_MIX_BYPASS);
gpio_set(PORT_NO_MIX_BYPASS, PIN_NO_MIX_BYPASS);
gpio_clear(PORT_TX_MIX_BP, PIN_TX_MIX_BP);
gpio_clear(PORT_RX_MIX_BP, PIN_RX_MIX_BP);
gpio_clear(rf_path->gpio_mix_bypass);
gpio_set(rf_path->gpio_no_mix_bypass);
gpio_clear(rf_path->gpio_tx_mix_bp);
gpio_clear(rf_path->gpio_rx_mix_bp);
}
if (ctrl & SWITCHCTRL_HP) {
gpio_set(PORT_HP, PIN_HP);
gpio_clear(PORT_LP, PIN_LP);
gpio_set(rf_path->gpio_hp);
gpio_clear(rf_path->gpio_lp);
} else {
gpio_clear(PORT_HP, PIN_HP);
gpio_set(PORT_LP, PIN_LP);
gpio_clear(rf_path->gpio_hp);
gpio_set(rf_path->gpio_lp);
}
if (ctrl & SWITCHCTRL_AMP_BYPASS) {
gpio_set(PORT_AMP_BYPASS, PIN_AMP_BYPASS);
gpio_clear(PORT_TX_AMP, PIN_TX_AMP);
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
gpio_clear(PORT_RX_AMP, PIN_RX_AMP);
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
gpio_set(rf_path->gpio_amp_bypass);
gpio_clear(rf_path->gpio_tx_amp);
gpio_set(rf_path->gpio_no_tx_amp_pwr);
gpio_clear(rf_path->gpio_rx_amp);
gpio_set(rf_path->gpio_no_rx_amp_pwr);
} else if (ctrl & SWITCHCTRL_TX) {
gpio_clear(PORT_AMP_BYPASS, PIN_AMP_BYPASS);
gpio_set(PORT_TX_AMP, PIN_TX_AMP);
gpio_clear(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
gpio_clear(PORT_RX_AMP, PIN_RX_AMP);
gpio_set(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
gpio_clear(rf_path->gpio_amp_bypass);
gpio_set(rf_path->gpio_tx_amp);
gpio_clear(rf_path->gpio_no_tx_amp_pwr);
gpio_clear(rf_path->gpio_rx_amp);
gpio_set(rf_path->gpio_no_rx_amp_pwr);
} else {
gpio_clear(PORT_AMP_BYPASS, PIN_AMP_BYPASS);
gpio_clear(PORT_TX_AMP, PIN_TX_AMP);
gpio_set(PORT_NO_TX_AMP_PWR, PIN_NO_TX_AMP_PWR);
gpio_set(PORT_RX_AMP, PIN_RX_AMP);
gpio_clear(PORT_NO_RX_AMP_PWR, PIN_NO_RX_AMP_PWR);
gpio_clear(rf_path->gpio_amp_bypass);
gpio_clear(rf_path->gpio_tx_amp);
gpio_set(rf_path->gpio_no_tx_amp_pwr);
gpio_set(rf_path->gpio_rx_amp);
gpio_clear(rf_path->gpio_no_rx_amp_pwr);
}
/*
@ -144,29 +143,29 @@ static void switchctrl_set_hackrf_one(uint8_t ctrl) {
* is unset:
*/
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)
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) {
rffc5071_set_gpo(0x00); /* turn on antenna power by clearing GPO1 */
rffc5071_set_gpo(&rffc5072, 0x00); /* turn on antenna power by clearing GPO1 */
} 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
static void switchctrl_set(const uint8_t gpo) {
static void switchctrl_set(rf_path_t* const rf_path, const uint8_t gpo) {
#ifdef JAWBREAKER
rffc5071_set_gpo(gpo);
rffc5071_set_gpo(&rffc5072, gpo);
#elif HACKRF_ONE
switchctrl_set_hackrf_one(gpo);
switchctrl_set_hackrf_one(rf_path, gpo);
#else
(void)gpo;
#endif
}
void rf_path_pin_setup() {
void rf_path_pin_setup(rf_path_t* const rf_path) {
#ifdef HACKRF_ONE
/* Configure RF switch control signals */
scu_pinmux(SCU_HP, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
@ -187,149 +186,152 @@ void rf_path_pin_setup() {
scu_pinmux(SCU_NO_VAA_ENABLE, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
/* Configure RF switch control signals as outputs */
GPIO0_DIR |= PIN_AMP_BYPASS;
GPIO1_DIR |= (PIN_NO_MIX_BYPASS | PIN_RX_AMP | PIN_NO_RX_AMP_PWR);
GPIO2_DIR |= (PIN_HP | PIN_LP | PIN_TX_MIX_BP | PIN_RX_MIX_BP | PIN_TX_AMP);
GPIO3_DIR |= PIN_NO_TX_AMP_PWR;
GPIO5_DIR |= (PIN_TX | PIN_MIX_BYPASS | PIN_RX);
gpio_output(rf_path->gpio_amp_bypass);
gpio_output(rf_path->gpio_no_mix_bypass);
gpio_output(rf_path->gpio_rx_amp);
gpio_output(rf_path->gpio_no_rx_amp_pwr);
gpio_output(rf_path->gpio_hp);
gpio_output(rf_path->gpio_lp);
gpio_output(rf_path->gpio_tx_mix_bp);
gpio_output(rf_path->gpio_rx_mix_bp);
gpio_output(rf_path->gpio_tx_amp);
gpio_output(rf_path->gpio_no_tx_amp_pwr);
gpio_output(rf_path->gpio_tx);
gpio_output(rf_path->gpio_mix_bypass);
gpio_output(rf_path->gpio_rx);
/*
* Safe (initial) switch settings turn off both amplifiers and antenna port
* power and enable both amp bypass and mixer bypass.
*/
switchctrl_set(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();
switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS);
#endif
}
void rf_path_init(void) {
void rf_path_init(rf_path_t* const rf_path) {
ssp1_set_mode_max5864();
max5864_shutdown();
max5864_setup(&max5864);
max5864_shutdown(&max5864);
ssp1_set_mode_max2837();
max2837_setup();
max2837_start();
max2837_setup(&max2837);
max2837_start(&max2837);
rffc5071_setup();
switchctrl_set(switchctrl);
rffc5071_setup(&rffc5072);
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. */
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) {
case RF_PATH_DIRECTION_TX:
switchctrl |= SWITCHCTRL_TX;
if( (switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
rf_path->switchctrl |= SWITCHCTRL_TX;
if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
/* 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();
if( switchctrl & SWITCHCTRL_MIX_BYPASS ) {
rffc5071_disable();
rffc5071_tx(&rffc5072);
if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
rffc5071_disable(&rffc5072);
} else {
rffc5071_enable();
rffc5071_enable(&rffc5072);
}
ssp1_set_mode_max5864();
max5864_tx();
max5864_tx(&max5864);
ssp1_set_mode_max2837();
max2837_tx();
sgpio_configure(SGPIO_DIRECTION_TX);
max2837_tx(&max2837);
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX);
break;
case RF_PATH_DIRECTION_RX:
switchctrl &= ~SWITCHCTRL_TX;
if( (switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
rf_path->switchctrl &= ~SWITCHCTRL_TX;
if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
/* 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();
if( switchctrl & SWITCHCTRL_MIX_BYPASS ) {
rffc5071_disable();
rffc5071_rx(&rffc5072);
if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
rffc5071_disable(&rffc5072);
} else {
rffc5071_enable();
rffc5071_enable(&rffc5072);
}
ssp1_set_mode_max5864();
max5864_rx();
max5864_rx(&max5864);
ssp1_set_mode_max2837();
max2837_rx();
sgpio_configure(SGPIO_DIRECTION_RX);
max2837_rx(&max2837);
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
break;
case RF_PATH_DIRECTION_OFF:
default:
#ifdef HACKRF_ONE
rf_path_set_antenna(0);
rf_path_set_antenna(rf_path, 0);
#endif
rf_path_set_lna(0);
rf_path_set_lna(rf_path, 0);
/* Set RF path to receive direction when "off" */
switchctrl &= ~SWITCHCTRL_TX;
rffc5071_disable();
rf_path->switchctrl &= ~SWITCHCTRL_TX;
rffc5071_disable(&rffc5072);
ssp1_set_mode_max5864();
max5864_standby();
max5864_standby(&max5864);
ssp1_set_mode_max2837();
max2837_set_mode(MAX2837_MODE_STANDBY);
sgpio_configure(SGPIO_DIRECTION_RX);
max2837_set_mode(&max2837, MAX2837_MODE_STANDBY);
sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
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) {
default:
case RF_PATH_FILTER_BYPASS:
switchctrl |= SWITCHCTRL_MIX_BYPASS;
rffc5071_disable();
rf_path->switchctrl |= SWITCHCTRL_MIX_BYPASS;
rffc5071_disable(&rffc5072);
break;
case RF_PATH_FILTER_LOW_PASS:
switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
rffc5071_enable();
rf_path->switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
rffc5071_enable(&rffc5072);
break;
case RF_PATH_FILTER_HIGH_PASS:
switchctrl &= ~SWITCHCTRL_MIX_BYPASS;
switchctrl |= SWITCHCTRL_HP;
rffc5071_enable();
rf_path->switchctrl &= ~SWITCHCTRL_MIX_BYPASS;
rf_path->switchctrl |= SWITCHCTRL_HP;
rffc5071_enable(&rffc5072);
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( switchctrl & SWITCHCTRL_TX ) {
if( rf_path->switchctrl & SWITCHCTRL_TX ) {
/* AMP_BYPASS=0, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=0 */
switchctrl |= SWITCHCTRL_NO_RX_AMP_PWR;
switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR);
rf_path->switchctrl |= SWITCHCTRL_NO_RX_AMP_PWR;
rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR);
} else {
/* AMP_BYPASS=0, NO_RX_AMP_PWR=0, NO_TX_AMP_PWR=1 */
switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR;
switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_RX_AMP_PWR);
rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR;
rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_RX_AMP_PWR);
}
} else {
/* AMP_BYPASS=1, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=1 */
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 */
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) {
switchctrl |= SWITCHCTRL_ANT_PWR;
rf_path->switchctrl |= SWITCHCTRL_ANT_PWR;
} 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>
void rf_path_pin_setup(void);
void rf_path_init(void);
#include "gpio.h"
typedef enum {
RF_PATH_DIRECTION_OFF,
@ -34,17 +33,39 @@ typedef enum {
RF_PATH_DIRECTION_TX,
} rf_path_direction_t;
void rf_path_set_direction(const rf_path_direction_t direction);
typedef enum {
RF_PATH_FILTER_BYPASS = 0,
RF_PATH_FILTER_LOW_PASS = 1,
RF_PATH_FILTER_HIGH_PASS = 2,
} 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_set_antenna(const uint_fast8_t enable);
void rf_path_pin_setup(rf_path_t* const rf_path);
void rf_path_init(rf_path_t* const rf_path);
void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t direction);
void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter);
void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable);
void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable);
#endif/*__RFPATH_H__*/

View File

@ -36,19 +36,10 @@
#include "rffc5071.h"
#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"
#endif
/* Default register values. */
static uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = {
static const uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = {
0xbefa, /* 00 */
0x4064, /* 01 */
0x9055, /* 02 */
@ -81,327 +72,139 @@ static uint16_t rffc5071_regs_default[RFFC5071_NUM_REGS] = {
0x1000, /* 1D */
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. */
void rffc5071_init(void)
void rffc5071_init(rffc5071_driver_t* const drv)
{
LOG("# rffc5071_init\n");
memcpy(rffc5071_regs, rffc5071_regs_default, sizeof(rffc5071_regs));
rffc5071_regs_dirty = 0x7fffffff;
memcpy(drv->regs, rffc5071_regs_default, sizeof(drv->regs));
drv->regs_dirty = 0x7fffffff;
/* 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 our own default register configuration.
*/
void rffc5071_setup(void)
void rffc5071_setup(rffc5071_driver_t* const drv)
{
rffc5071_init();
LOG("# rffc5071_setup\n");
#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);
gpio_set(drv->gpio_reset);
gpio_output(drv->gpio_reset);
/* Set GPIO pins as outputs. */
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
rffc5071_init(drv);
/* initial setup */
/* put zeros in freq contol registers */
set_RFFC5071_P2N(0);
set_RFFC5071_P2LODIV(0);
set_RFFC5071_P2PRESC(0);
set_RFFC5071_P2VCOSEL(0);
set_RFFC5071_P2N(drv, 0);
set_RFFC5071_P2LODIV(drv, 0);
set_RFFC5071_P2PRESC(drv, 0);
set_RFFC5071_P2VCOSEL(drv, 0);
set_RFFC5071_P2N(0);
set_RFFC5071_P2LODIV(0);
set_RFFC5071_P2PRESC(0);
set_RFFC5071_P2VCOSEL(0);
set_RFFC5071_P2N(drv, 0);
set_RFFC5071_P2LODIV(drv, 0);
set_RFFC5071_P2PRESC(drv, 0);
set_RFFC5071_P2VCOSEL(drv, 0);
set_RFFC5071_P2N(0);
set_RFFC5071_P2LODIV(0);
set_RFFC5071_P2PRESC(0);
set_RFFC5071_P2VCOSEL(0);
set_RFFC5071_P2N(drv, 0);
set_RFFC5071_P2LODIV(drv, 0);
set_RFFC5071_P2PRESC(drv, 0);
set_RFFC5071_P2VCOSEL(drv, 0);
/* set ENBL and MODE to be configured via 3-wire interface,
* not control pins. */
set_RFFC5071_SIPIN(1);
set_RFFC5071_SIPIN(drv, 1);
/* 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)
{
uint32_t i;
static uint16_t rffc5071_spi_read(rffc5071_driver_t* const drv, uint8_t r) {
(void)drv;
for (i = 0; i < 2; i++)
__asm__("nop");
uint16_t data[] = { 0x80 | (r & 0x7f), 0xffff };
spi_bus_transfer(drv->bus, data, 2);
return data[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).
*/
uint16_t rffc5071_spi_read(uint8_t r) {
static void rffc5071_spi_write(rffc5071_driver_t* const drv, uint8_t r, uint16_t v) {
(void)drv;
int bits = 9;
int msb = 1 << (bits -1);
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);
uint16_t data[] = { 0x00 | (r & 0x7f), v };
spi_bus_transfer(drv->bus, data, 2);
}
serial_delay();
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)
uint16_t rffc5071_reg_read(rffc5071_driver_t* const drv, uint8_t r)
{
/* Readback register is not cached. */
if (r == RFFC5071_READBACK_REG)
return rffc5071_spi_read(r);
return rffc5071_spi_read(drv, r);
/* Discard uncommited write when reading. This shouldn't
* happen, and probably has not been tested. */
if ((rffc5071_regs_dirty >> r) & 0x1) {
rffc5071_regs[r] = rffc5071_spi_read(r);
if ((drv->regs_dirty >> r) & 0x1) {
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;
rffc5071_spi_write(r, v);
RFFC5071_REG_SET_CLEAN(r);
drv->regs[r] = v;
rffc5071_spi_write(drv, r, v);
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;
for(r = 0; r < RFFC5071_NUM_REGS; r++) {
if ((rffc5071_regs_dirty >> r) & 0x1) {
rffc5071_reg_commit(r);
if ((drv->regs_dirty >> r) & 0x1) {
rffc5071_reg_commit(drv, r);
}
}
}
void rffc5071_tx(void) {
LOG("# rffc5071_tx\n");
set_RFFC5071_ENBL(0);
set_RFFC5071_FULLD(0);
set_RFFC5071_MODE(1); /* mixer 2 used for both RX and TX */
rffc5071_regs_commit();
void rffc5071_tx(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_FULLD(drv, 0);
set_RFFC5071_MODE(drv, 1); /* mixer 2 used for both RX and TX */
rffc5071_regs_commit(drv);
}
void rffc5071_rx(void) {
LOG("# rfc5071_rx\n");
set_RFFC5071_ENBL(0);
set_RFFC5071_FULLD(0);
set_RFFC5071_MODE(1); /* mixer 2 used for both RX and TX */
rffc5071_regs_commit();
void rffc5071_rx(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_FULLD(drv, 0);
set_RFFC5071_MODE(drv, 1); /* mixer 2 used for both RX and TX */
rffc5071_regs_commit(drv);
}
/*
* This function turns on both mixer (full-duplex) on the RFFC5071, but our
* current hardware designs do not support full-duplex operation.
*/
void rffc5071_rxtx(void) {
LOG("# rfc5071_rxtx\n");
set_RFFC5071_ENBL(0);
set_RFFC5071_FULLD(1); /* mixer 1 and mixer 2 (RXTX) */
rffc5071_regs_commit();
void rffc5071_rxtx(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 0);
set_RFFC5071_FULLD(drv, 1); /* mixer 1 and mixer 2 (RXTX) */
rffc5071_regs_commit(drv);
rffc5071_enable();
rffc5071_enable(drv);
}
void rffc5071_disable(void) {
LOG("# rfc5071_disable\n");
set_RFFC5071_ENBL(0);
rffc5071_regs_commit();
void rffc5071_disable(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 0);
rffc5071_regs_commit(drv);
}
void rffc5071_enable(void) {
LOG("# rfc5071_enable\n");
set_RFFC5071_ENBL(1);
rffc5071_regs_commit();
void rffc5071_enable(rffc5071_driver_t* const drv) {
set_RFFC5071_ENBL(drv, 1);
rffc5071_regs_commit(drv);
}
#define LO_MAX 5400
@ -409,7 +212,7 @@ void rffc5071_enable(void) {
#define FREQ_ONE_MHZ (1000*1000)
/* 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;
uint16_t fvco;
uint8_t fbkdiv;
@ -418,8 +221,6 @@ uint64_t rffc5071_config_synth_int(uint16_t lo) {
uint16_t p1nmsb;
uint8_t p1nlsb;
LOG("# config_synth_int\n");
/* Calculate n_lo */
uint8_t n_lo = 0;
uint16_t x = LO_MAX / lo;
@ -438,10 +239,10 @@ uint64_t rffc5071_config_synth_int(uint16_t lo) {
* and will be unaffected. */
if (fvco > 3200) {
fbkdiv = 4;
set_RFFC5071_PLLCPL(3);
set_RFFC5071_PLLCPL(drv, 3);
} else {
fbkdiv = 2;
set_RFFC5071_PLLCPL(2);
set_RFFC5071_PLLCPL(drv, 2);
}
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)
/ (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 */
set_RFFC5071_P1LODIV(n_lo);
set_RFFC5071_P1N(n);
set_RFFC5071_P1PRESC(fbkdiv >> 1);
set_RFFC5071_P1NMSB(p1nmsb);
set_RFFC5071_P1NLSB(p1nlsb);
set_RFFC5071_P1LODIV(drv, n_lo);
set_RFFC5071_P1N(drv, n);
set_RFFC5071_P1PRESC(drv, fbkdiv >> 1);
set_RFFC5071_P1NMSB(drv, p1nmsb);
set_RFFC5071_P1NLSB(drv, p1nlsb);
/* Path 2 */
set_RFFC5071_P2LODIV(n_lo);
set_RFFC5071_P2N(n);
set_RFFC5071_P2PRESC(fbkdiv >> 1);
set_RFFC5071_P2NMSB(p1nmsb);
set_RFFC5071_P2NLSB(p1nlsb);
set_RFFC5071_P2LODIV(drv, n_lo);
set_RFFC5071_P2N(drv, n);
set_RFFC5071_P2PRESC(drv, fbkdiv >> 1);
set_RFFC5071_P2NMSB(drv, p1nmsb);
set_RFFC5071_P2NLSB(drv, p1nlsb);
rffc5071_regs_commit();
rffc5071_regs_commit(drv);
return tune_freq_hz;
}
/* !!!!!!!!!!! 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;
rffc5071_disable();
tune_freq = rffc5071_config_synth_int(mhz);
rffc5071_enable();
rffc5071_disable(drv);
tune_freq = rffc5071_config_synth_int(drv, mhz);
rffc5071_enable(drv);
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. */
set_RFFC5071_P1GPO(gpo);
set_RFFC5071_P2GPO(gpo);
set_RFFC5071_P1GPO(drv, 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
#define __RFFC5071_H
#include <stdint.h>
#include "spi_bus.h"
#include "gpio.h"
/* 31 registers, each containing 16 bits of data. */
#define RFFC5071_NUM_REGS 31
extern uint16_t rffc5071_regs[RFFC5071_NUM_REGS];
extern uint32_t rffc5071_regs_dirty;
#define RFFC5071_REG_SET_CLEAN(r) rffc5071_regs_dirty &= ~(1UL<<r)
#define RFFC5071_REG_SET_DIRTY(r) rffc5071_regs_dirty |= (1UL<<r)
typedef struct {
spi_bus_t* const bus;
gpio_t gpio_reset;
uint16_t regs[RFFC5071_NUM_REGS];
uint32_t regs_dirty;
} rffc5071_driver_t;
/* Initialize chip. Call _setup() externally, as it calls _init(). */
extern void rffc5071_init(void);
extern void rffc5071_setup(void);
extern void rffc5071_init(rffc5071_driver_t* const drv);
extern void rffc5071_setup(rffc5071_driver_t* const drv);
/* Read a register via SPI. Save a copy to memory and return
* value. Discard any uncommited changes and mark CLEAN. */
extern uint16_t rffc5071_reg_read(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
* 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
* operations require registers to be written in a certain order. Use
* provided routines for those operations. */
extern void rffc5071_regs_commit(void);
extern void rffc5071_regs_commit(rffc5071_driver_t* const drv);
/* 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
* before _tx, _rx, or _rxtx are called. */
extern void rffc5071_tx(void);
extern void rffc5071_rx(void);
extern void rffc5071_rxtx(void);
extern void rffc5071_enable(void);
extern void rffc5071_disable(void);
extern void rffc5071_tx(rffc5071_driver_t* const drv);
extern void rffc5071_rx(rffc5071_driver_t* const drv);
extern void rffc5071_rxtx(rffc5071_driver_t* const drv);
extern void rffc5071_enable(rffc5071_driver_t* const drv);
extern void rffc5071_disable(rffc5071_driver_t* const drv);
extern void rffc5071_set_gpo(uint8_t);
extern void rffc5071_set_gpo(rffc5071_driver_t* const drv, uint8_t);
#endif // __RFFC5071_H

View File

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

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
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)
{
@ -92,7 +93,7 @@ isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res)
/* Only 64bits used */
iap_cmd_res->status_res.iap_result[0] = 0;
iap_cmd_res->status_res.iap_result[1] = 0;
w25q80bv_get_unique_id( (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;
break;

View File

@ -20,7 +20,6 @@
* Boston, MA 02110-1301, USA.
*/
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/sgpio.h>
@ -28,9 +27,7 @@
#include <sgpio.h>
static bool sgpio_slice_mode_multislice = true;
void sgpio_configure_pin_functions() {
void sgpio_configure_pin_functions(sgpio_config_t* const config) {
scu_pinmux(SCU_PINMUX_SGPIO0, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
scu_pinmux(SCU_PINMUX_SGPIO1, SCU_GPIO_FAST | SCU_CONF_FUNCTION3);
scu_pinmux(SCU_PINMUX_SGPIO2, SCU_GPIO_FAST | SCU_CONF_FUNCTION2);
@ -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_SGPIO15, SCU_GPIO_FAST | SCU_CONF_FUNCTION4); /* GPIO5[14] */
sgpio_cpld_stream_rx_set_decimation(1);
sgpio_cpld_stream_rx_set_q_invert(0);
sgpio_cpld_stream_rx_set_decimation(config, 1);
sgpio_cpld_stream_rx_set_q_invert(config, 0);
GPIO_DIR(GPIO0) |= GPIOPIN13;
GPIO_DIR(GPIO5) |= GPIOPIN14 | GPIOPIN13 | GPIOPIN12;
}
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);
}
}
gpio_output(config->gpio_rx_q_invert);
gpio_output(config->gpio_rx_decimation[0]);
gpio_output(config->gpio_rx_decimation[1]);
gpio_output(config->gpio_rx_decimation[2]);
}
void sgpio_set_slice_mode(
sgpio_config_t* const config,
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)
*/
void sgpio_configure(
sgpio_config_t* const config,
const sgpio_direction_t direction
) {
// Disable all counters during configuration
@ -167,7 +124,7 @@ void sgpio_configure(
;
const uint_fast8_t output_multiplexing_mode =
sgpio_slice_mode_multislice ? 11 : 9;
config->slice_mode_multislice ? 11 : 9;
/* SGPIO0 to SGPIO7 */
for(uint_fast8_t i=0; i<8; i++) {
// SGPIO pin 0 outputs slice A bit "i".
@ -189,9 +146,9 @@ void sgpio_configure(
};
const uint_fast8_t slice_gpdma = SGPIO_SLICE_H;
const uint_fast8_t pos = sgpio_slice_mode_multislice ? 0x1f : 0x03;
const bool single_slice = !sgpio_slice_mode_multislice;
const uint_fast8_t slice_count = sgpio_slice_mode_multislice ? 8 : 1;
const uint_fast8_t pos = config->slice_mode_multislice ? 0x1f : 0x03;
const bool single_slice = !config->slice_mode_multislice;
const uint_fast8_t slice_count = config->slice_mode_multislice ? 8 : 1;
const uint_fast8_t clk_capture_mode = (direction == SGPIO_DIRECTION_TX) ? 0 : 1;
uint32_t slice_enable_mask = 0;
@ -236,7 +193,7 @@ void sgpio_configure(
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_CONCAT_ORDER(0) /* Self-loop */
| SGPIO_MUX_CFG_CONCAT_ENABLE(1)
@ -274,21 +231,24 @@ void sgpio_configure(
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.
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.
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 */
}
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]:
* 111: decimate by 1 (skip_n=0, skip no samples)
* 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)
*/
const uint_fast8_t skip_n = n - 1;
GPIO_SET(GPIO5) = GPIOPIN14 | GPIOPIN13 | GPIOPIN12;
GPIO_CLR(GPIO5) = (skip_n & 7) << 12;
gpio_write(config->gpio_rx_decimation[0], (skip_n & 1) == 0);
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);
}
void sgpio_cpld_stream_rx_set_q_invert(const uint_fast8_t invert) {
if( invert ) {
GPIO_SET(GPIO0) = GPIOPIN13;
} else {
GPIO_CLR(GPIO0) = GPIOPIN13;
}
void sgpio_cpld_stream_rx_set_q_invert(sgpio_config_t* const config, const uint_fast8_t invert) {
gpio_write(config->gpio_rx_q_invert, invert);
}

View File

@ -22,26 +22,39 @@
#ifndef __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 {
SGPIO_DIRECTION_RX,
SGPIO_DIRECTION_TX,
} sgpio_direction_t;
void sgpio_configure_pin_functions();
void sgpio_test_interface();
typedef struct sgpio_config_t {
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(
sgpio_config_t* const config,
const bool multi_slice
);
void sgpio_configure(
sgpio_config_t* const config,
const sgpio_direction_t direction
);
void sgpio_cpld_stream_enable();
void sgpio_cpld_stream_disable();
bool sgpio_cpld_stream_is_enabled();
void sgpio_cpld_stream_enable(sgpio_config_t* const config);
void sgpio_cpld_stream_disable(sgpio_config_t* const config);
bool sgpio_cpld_stream_is_enabled(sgpio_config_t* const config);
bool sgpio_cpld_stream_rx_set_decimation(const uint_fast8_t n);
void sgpio_cpld_stream_rx_set_q_invert(const uint_fast8_t invert);
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(sgpio_config_t* const config, const uint_fast8_t invert);
#endif//__SGPIO_H__

View File

@ -21,73 +21,50 @@
*/
#include "si5351c.h"
#include <libopencm3/lpc43xx/i2c.h>
enum pll_sources active_clock_source;
/* FIXME return i2c0 status from each function */
/* 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();
i2c0_tx_byte(SI5351C_I2C_ADDR | I2C_WRITE);
i2c0_tx_byte(reg);
i2c0_tx_byte(val);
i2c0_stop();
const uint8_t data_tx[] = { reg, val };
si5351c_write(drv, data_tx, 2);
}
/* 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;
/* set register address with write */
i2c0_tx_start();
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;
const uint8_t data_tx[] = { reg };
uint8_t data_rx[] = { 0x00 };
i2c_bus_transfer(drv->bus, drv->i2c_address, data_tx, 1, data_rx, 1);
return data_rx[0];
}
/*
* Write to one or more contiguous registers. data[0] should be the first
* register number, one or more values follow.
*/
void si5351c_write(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;
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();
i2c_bus_transfer(drv->bus, drv->i2c_address, data, data_count, NULL, 0);
}
/* Disable all CLKx outputs. */
void si5351c_disable_all_outputs()
void si5351c_disable_all_outputs(si5351c_driver_t* const drv)
{
uint8_t data[] = { 3, 0xFF };
si5351c_write(data, sizeof(data));
si5351c_write(drv, data, sizeof(data));
}
/* 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 };
si5351c_write(data, sizeof(data));
si5351c_write(drv, data, sizeof(data));
}
/* 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
, 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_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
* 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 };
si5351c_write(data, sizeof(data));
si5351c_write(drv, data, sizeof(data));
}
/*
* Register 187: Fanout Enable
* 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 };
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)
* 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 };
si5351c_write(data, sizeof(data));
si5351c_write(drv, data, sizeof(data));
}
/* 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
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 */
data[0] = 34;
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 */
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 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),
(p2 >> 8) & 0xFF,
(p2 >> 0) & 0xFF };
si5351c_write(data, sizeof(data));
si5351c_write(drv, data, sizeof(data));
}
#ifdef JELLYBEAN
@ -232,15 +210,15 @@ void si5351c_configure_multisynth(const uint_fast8_t ms_number,
* CLK5_SRC=3 (MS5 as input source)
* 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 };
si5351c_write(data, sizeof(data));
si5351c_write(drv, data, sizeof(data));
}
#endif
#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;
@ -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_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
/* 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 };
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};
if(ms_number < 8){
data[0] = 16 + ms_number;
data[1] = si5351c_read_single(data[0]);
data[1] = si5351c_read_single(drv, data[0]);
if(on)
data[1] |= SI5351C_CLK_INT_MODE;
else
data[1] &= ~(SI5351C_CLK_INT_MODE);
si5351c_write(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;
}
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) {
/* CLKIN not detected */
if (active_clock_source == PLL_SOURCE_CLKIN) {
si5351c_set_clock_source(PLL_SOURCE_XTAL);
si5351c_set_clock_source(drv, PLL_SOURCE_XTAL);
}
} else {
/* CLKIN detected */
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 "i2c_bus.h"
#define SI_INTDIV(x) (x*128-512)
#define SI5351C_I2C_ADDR (0x60 << 1)
#define SI5351C_CLK_POWERDOWN (1<<7)
#define SI5351C_CLK_INT_MODE (1<<6)
@ -62,26 +63,32 @@ enum pll_sources {
PLL_SOURCE_CLKIN = 1,
};
void si5351c_disable_all_outputs();
void si5351c_disable_oeb_pin_control();
void si5351c_power_down_all_clocks();
void si5351c_set_crystal_configuration();
void si5351c_enable_xo_and_ms_fanout();
void si5351c_configure_pll_sources(void);
void si5351c_configure_pll_multisynth(void);
void si5351c_reset_pll(void);
void si5351c_configure_multisynth(const uint_fast8_t ms_number,
typedef struct {
i2c_bus_t* const bus;
uint8_t i2c_address;
} si5351c_driver_t;
void si5351c_disable_all_outputs(si5351c_driver_t* const drv);
void si5351c_disable_oeb_pin_control(si5351c_driver_t* const drv);
void si5351c_power_down_all_clocks(si5351c_driver_t* const drv);
void si5351c_set_crystal_configuration(si5351c_driver_t* const drv);
void si5351c_enable_xo_and_ms_fanout(si5351c_driver_t* const drv);
void si5351c_configure_pll_sources(si5351c_driver_t* const drv);
void si5351c_configure_pll_multisynth(si5351c_driver_t* const drv);
void si5351c_reset_pll(si5351c_driver_t* const drv);
void si5351c_configure_multisynth(si5351c_driver_t* const drv,
const uint_fast8_t ms_number,
const uint32_t p1, const uint32_t p2, const uint32_t p3,
const uint_fast8_t r_div);
void si5351c_configure_clock_control(const enum pll_sources source);
void si5351c_enable_clock_outputs();
void si5351c_set_int_mode(const uint_fast8_t ms_number, const uint_fast8_t on);
void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll_sources source);
void si5351c_enable_clock_outputs(si5351c_driver_t* const drv);
void si5351c_set_int_mode(si5351c_driver_t* const drv, const uint_fast8_t ms_number, const uint_fast8_t on);
void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source);
void si5351c_activate_best_clock_source(si5351c_driver_t* const drv);
void si5351c_write_single(uint8_t reg, uint8_t val);
uint8_t si5351c_read_single(uint8_t reg);
void si5351c_write(uint8_t* const data, const uint_fast8_t data_count);
void si5351c_set_clock_source(const enum pll_sources source);
void si5351c_activate_best_clock_source(void);
void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val);
uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg);
void si5351c_write(si5351c_driver_t* const drv, const uint8_t* const data, const size_t data_count);
#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/sgpio.h>
#include <sgpio.h>
void baseband_streaming_enable() {
void baseband_streaming_enable(sgpio_config_t* const sgpio_config) {
nvic_set_priority(NVIC_SGPIO_IRQ, 0);
nvic_enable_irq(NVIC_SGPIO_IRQ);
SGPIO_SET_EN_1 = (1 << SGPIO_SLICE_A);
sgpio_cpld_stream_enable();
sgpio_cpld_stream_enable(sgpio_config);
}
void baseband_streaming_disable() {
sgpio_cpld_stream_disable();
void baseband_streaming_disable(sgpio_config_t* const sgpio_config) {
sgpio_cpld_stream_disable(sgpio_config);
nvic_disable_irq(NVIC_SGPIO_IRQ);
}

View File

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

View File

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

View File

@ -1,6 +1,7 @@
/*
* Copyright 2013 Michael Ossmann
* Copyright 2013 Benjamin Vernoux
* Copyright 2014 Jared Boone, ShareBrained Technology
*
* This file is part of HackRF.
*
@ -27,183 +28,139 @@
*/
#include <stdint.h>
#include <stddef.h>
#include "w25q80bv.h"
#include "hackrf_core.h"
#include <libopencm3/lpc43xx/ssp.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/rgu.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define W25Q80BV_READ_DATA 0x03
#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.
* SSP0_SSEL is controlled by GPIO in order to handle various transfer lengths.
*/
void w25q80bv_setup(void)
void w25q80bv_setup(w25q80bv_driver_t* const drv)
{
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 */
RESET_CTRL1 = RESET_CTRL1_SPIFI_RST;
drv->page_len = 256U;
drv->num_pages = 4096U;
drv->num_bytes = 1048576U;
/* 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(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);
drv->target_init(drv);
device_id = 0;
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;
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
ssp_transfer(SSP0_NUM, W25Q80BV_READ_STATUS1);
value = ssp_transfer(SSP0_NUM, 0xFF);
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
return value;
uint8_t data[] = { W25Q80BV_READ_STATUS1, 0xFF };
spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
return data[1];
}
/* 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;
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
ssp_transfer(SSP0_NUM, W25Q80BV_DEVICE_ID);
/* Read 3 dummy bytes */
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;
uint8_t data[] = {
W25Q80BV_DEVICE_ID,
0xFF, 0xFF, 0xFF, 0xFF
};
spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
return data[4];
}
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 value;
uint8_t data[] = {
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);
ssp_transfer(SSP0_NUM, W25Q80BV_UNIQUE_ID);
/* 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;
for(size_t i=0; i<8; i++) {
unique_id->id_8b[i] = data[5+i];
}
}
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
}
void w25q80bv_wait_while_busy(void)
void w25q80bv_wait_while_busy(w25q80bv_driver_t* const drv)
{
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();
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
ssp_transfer(SSP0_NUM, W25Q80BV_WRITE_ENABLE);
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
w25q80bv_wait_while_busy(drv);
uint8_t data[] = { W25Q80BV_WRITE_ENABLE };
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;
device_id = 0;
while(device_id != W25Q80BV_DEVICE_ID_RES)
{
device_id = w25q80bv_get_device_id();
device_id = w25q80bv_get_device_id(drv);
}
w25q80bv_write_enable();
w25q80bv_wait_while_busy();
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
ssp_transfer(SSP0_NUM, W25Q80BV_CHIP_ERASE);
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
w25q80bv_write_enable(drv);
w25q80bv_wait_while_busy(drv);
uint8_t data[] = { W25Q80BV_CHIP_ERASE };
spi_bus_transfer(drv->bus, data, ARRAY_SIZE(data));
}
/* 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 */
if (((addr & 0xFF) + len) > W25Q80BV_PAGE_LEN)
if (((addr & 0xFF) + len) > drv->page_len)
return;
/* do nothing if we would overflow the flash */
if (addr > (W25Q80BV_NUM_BYTES - len))
if (addr > (drv->num_bytes - len))
return;
w25q80bv_write_enable();
w25q80bv_wait_while_busy();
w25q80bv_write_enable(drv);
w25q80bv_wait_while_busy(drv);
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
ssp_transfer(SSP0_NUM, W25Q80BV_PAGE_PROGRAM);
ssp_transfer(SSP0_NUM, (addr & 0xFF0000) >> 16);
ssp_transfer(SSP0_NUM, (addr & 0xFF00) >> 8);
ssp_transfer(SSP0_NUM, addr & 0xFF);
for (i = 0; i < len; i++)
ssp_transfer(SSP0_NUM, data[i]);
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
uint8_t header[] = {
W25Q80BV_PAGE_PROGRAM,
(addr & 0xFF0000) >> 16,
(addr & 0xFF00) >> 8,
addr & 0xFF
};
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 */
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;
uint8_t device_id;
@ -211,57 +168,60 @@ void w25q80bv_program(uint32_t addr, uint32_t len, const uint8_t* data)
device_id = 0;
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 */
if ((len > W25Q80BV_NUM_BYTES) || (addr > W25Q80BV_NUM_BYTES)
|| ((addr + len) > W25Q80BV_NUM_BYTES))
if ((len > drv->num_bytes) || (addr > drv->num_bytes)
|| ((addr + len) > drv->num_bytes))
return;
/* 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)
first_block_len = 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;
data += first_block_len;
len -= first_block_len;
}
/* one page at a time on boundaries */
while (len >= W25Q80BV_PAGE_LEN) {
w25q80bv_page_program(addr, W25Q80BV_PAGE_LEN, data);
addr += W25Q80BV_PAGE_LEN;
data += W25Q80BV_PAGE_LEN;
len -= W25Q80BV_PAGE_LEN;
while (len >= drv->page_len) {
w25q80bv_page_program(drv, addr, drv->page_len, data);
addr += drv->page_len;
data += drv->page_len;
len -= drv->page_len;
}
/* handle end not at page boundary */
if (len) {
w25q80bv_page_program(addr, len, data);
w25q80bv_page_program(drv, addr, len, data);
}
}
void w25q80bv_read(uint32_t addr, uint32_t len, uint8_t* const data)
/* write an arbitrary number of bytes */
void w25q80bv_read(w25q80bv_driver_t* const drv, uint32_t addr, uint32_t len, uint8_t* const data)
{
uint32_t i;
/* do nothing if we would overflow the flash */
if ((len > W25Q80BV_NUM_BYTES) || (addr > W25Q80BV_NUM_BYTES)
|| ((addr + len) > W25Q80BV_NUM_BYTES))
if ((len > drv->num_bytes) || (addr > drv->num_bytes)
|| ((addr + len) > drv->num_bytes))
return;
w25q80bv_wait_while_busy();
w25q80bv_wait_while_busy(drv);
gpio_clear(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
ssp_transfer(SSP0_NUM, W25Q80BV_FAST_READ);
ssp_transfer(SSP0_NUM, (addr >> 16) & 0xFF);
ssp_transfer(SSP0_NUM, (addr >> 8) & 0xFF);
ssp_transfer(SSP0_NUM, (addr >> 0) & 0xFF);
ssp_transfer(SSP0_NUM, 0xFF);
for (i = 0; i < len; i++)
data[i] = ssp_transfer(SSP0_NUM, 0xFF);
gpio_set(PORT_SSP0_SSEL, PIN_SSP0_SSEL);
uint8_t header[] = {
W25Q80BV_FAST_READ,
(addr & 0xFF0000) >> 16,
(addr & 0xFF00) >> 8,
addr & 0xFF
};
const spi_transfer_t transfers[] = {
{ header, ARRAY_SIZE(header) },
{ data, len }
};
spi_bus_transfer_gather(drv->bus, transfers, ARRAY_SIZE(transfers));
}

View File

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

View File

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

View File

@ -13,7 +13,8 @@
#include "hackrf_core.h"
#include "cpld_jtag.h"
#include <libopencm3/lpc43xx/gpio.h>
#include "gpio.h"
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).*/
/* 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 (val)
gpio_set(PORT_CPLD_TMS, PIN_CPLD_TMS);
gpio_set(gpio->gpio_tms);
else
gpio_clear(PORT_CPLD_TMS, PIN_CPLD_TMS);
gpio_clear(gpio->gpio_tms);
} if (p==TDI) {
if (val)
gpio_set(PORT_CPLD_TDI, PIN_CPLD_TDI);
gpio_set(gpio->gpio_tdi);
else
gpio_clear(PORT_CPLD_TDI, PIN_CPLD_TDI);
gpio_clear(gpio->gpio_tdi);
} if (p==TCK) {
if (val)
gpio_set(PORT_CPLD_TCK, PIN_CPLD_TCK);
gpio_set(gpio->gpio_tck);
else
gpio_clear(PORT_CPLD_TCK, PIN_CPLD_TCK);
gpio_clear(gpio->gpio_tck);
}
/* 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. */
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);
setPort(TCK,1); /* set the TCK port to high */
setPort(gpio, TCK,1); /* set the TCK port to high */
delay_jtag(200);
}
@ -81,10 +82,10 @@ void readByte(unsigned char *data)
/* readTDOBit: Implement to return the current value of the JTAG TDO signal.*/
/* read the TDO bit from port */
unsigned char readTDOBit()
unsigned char readTDOBit(jtag_gpio_t* const gpio)
{
delay_jtag(2000);
return CPLD_TDO_STATE;
return gpio_read(gpio->gpio_tdo);;
}
/* waitTime: Implement as follows: */
@ -96,7 +97,7 @@ unsigned char readTDOBit()
/* RECOMMENDED IMPLEMENTATION: Pulse TCK at least microsec times AND */
/* continue pulsing TCK until the microsec wait */
/* 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 */
long tckCycles = microsec * tckCyclesPerMicrosec;
@ -108,6 +109,6 @@ void waitTime(long microsec)
in order to satisfy the microsec wait time requirement. */
for ( i = 0; i < tckCycles; ++i )
{
pulseClock();
pulseClock(gpio);
}
}

View File

@ -7,6 +7,8 @@
#ifndef ports_dot_h
#define ports_dot_h
#include "cpld_jtag.h"
/* these constants are used to send the appropriate ports to setPort */
/* they should be enumerated types, but some of the microcontroller */
/* compilers don't like enumerated types */
@ -15,17 +17,17 @@
#define TDI (short) 2
/* 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 */
extern unsigned char readTDOBit();
extern unsigned char readTDOBit(jtag_gpio_t* const gpio);
/* 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 */
extern void readByte(unsigned char *data);
extern void waitTime(long microsec);
extern void waitTime(jtag_gpio_t* const gpio, long microsec);
#endif

View File

@ -135,8 +135,18 @@ macro(DeclareTargets)
${PATH_HACKRF_FIRMWARE_COMMON}/rf_path.c
${PATH_HACKRF_FIRMWARE_COMMON}/si5351c.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_target.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
)

View File

@ -44,7 +44,6 @@ set(SRC_M4
usb_api_transceiver.c
"${PATH_HACKRF_FIRMWARE_COMMON}/usb_queue.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}/xapp058/lenval.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/micro.c"

View File

@ -24,7 +24,6 @@
#include <libopencm3/cm3/vector.h>
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/m4/nvic.h>
#include <streaming.h>
@ -43,16 +42,13 @@
#include "usb_api_spiflash.h"
#include "usb_api_transceiver.h"
#include "rf_path.h"
#include "sgpio_isr.h"
#include "usb_bulk_buffer.h"
#include "si5351c.h"
#include "w25q80bv.h"
static volatile transceiver_mode_t _transceiver_mode = TRANSCEIVER_MODE_OFF;
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_out);
@ -60,27 +56,27 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
_transceiver_mode = new_transceiver_mode;
if( _transceiver_mode == TRANSCEIVER_MODE_RX ) {
gpio_clear(PORT_LED1_3, PIN_LED3);
gpio_set(PORT_LED1_3, PIN_LED2);
led_off(LED3);
led_on(LED2);
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;
} else if (_transceiver_mode == TRANSCEIVER_MODE_TX) {
gpio_clear(PORT_LED1_3, PIN_LED2);
gpio_set(PORT_LED1_3, PIN_LED3);
led_off(LED2);
led_on(LED3);
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;
} else {
gpio_clear(PORT_LED1_3, PIN_LED2);
gpio_clear(PORT_LED1_3, PIN_LED3);
rf_path_set_direction(RF_PATH_DIRECTION_OFF);
led_off(LED2);
led_off(LED3);
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF);
vector_table.irq[NVIC_SGPIO_IRQ] = sgpio_isr_rx;
}
if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) {
si5351c_activate_best_clock_source();
baseband_streaming_enable();
si5351c_activate_best_clock_source(&clock_gen);
baseband_streaming_enable(&sgpio_config);
}
}
@ -179,7 +175,7 @@ void usb_configuration_changed(
if( device->configuration->number == 1 ) {
// transceiver configuration
cpu_clock_pll1_max_speed();
gpio_set(PORT_LED1_3, PIN_LED1);
led_on(LED1);
} else if( device->configuration->number == 2 ) {
// CPLD update configuration
cpu_clock_pll1_max_speed();
@ -188,7 +184,7 @@ void usb_configuration_changed(
} else {
/* Configuration number equal 0 means usb bus reset. */
cpu_clock_pll1_low_speed();
gpio_clear(PORT_LED1_3, PIN_LED1);
led_off(LED1);
}
}
@ -225,9 +221,6 @@ int main(void) {
#endif
cpu_clock_init();
/* Code is not running from SPI flash, initialize for flash read/write over USB */
w25q80bv_setup();
usb_set_descriptor_by_serial_number();
usb_set_configuration_changed_cb(usb_configuration_changed);
@ -247,9 +240,7 @@ int main(void) {
usb_run(&usb_device);
ssp1_init();
rf_path_init();
rf_path_init(&rf_path);
unsigned int phase = 0;
while(true) {

View File

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

View File

@ -22,14 +22,16 @@
#include "usb_api_register.h"
#include <hackrf_core.h>
#include <usb_queue.h>
#include <max2837.h>
#include <si5351c.h>
#include <rffc5071.h>
#include <stddef.h>
#include <stdint.h>
#include <hackrf_core.h>
usb_request_status_t usb_vendor_request_write_max2837(
usb_endpoint_t* const endpoint,
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( endpoint->setup.index < MAX2837_NUM_REGS ) {
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);
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( 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[1] = value >> 8;
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( endpoint->setup.index < 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);
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( 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;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
@ -113,7 +115,7 @@ usb_request_status_t usb_vendor_request_write_rffc5071(
{
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);
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 )
{
value = rffc5071_reg_read(endpoint->setup.index);
value = rffc5071_reg_read(&rffc5072, endpoint->setup.index);
endpoint->buffer[0] = value & 0xff;
endpoint->buffer[1] = value >> 8;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2,

View File

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

View File

@ -22,8 +22,6 @@
#include "usb_api_transceiver.h"
#include <libopencm3/lpc43xx/gpio.h>
#include <max2837.h>
#include <rf_path.h>
#include <tuning.h>
@ -125,11 +123,11 @@ usb_request_status_t usb_vendor_request_set_amp_enable(
if (stage == USB_TRANSFER_STAGE_SETUP) {
switch (endpoint->setup.value) {
case 0:
rf_path_set_lna(0);
rf_path_set_lna(&rf_path, 0);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
case 1:
rf_path_set_lna(1);
rf_path_set_lna(&rf_path, 1);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
default:
@ -145,7 +143,7 @@ usb_request_status_t usb_vendor_request_set_lna_gain(
const usb_transfer_stage_t stage)
{
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;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
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)
{
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;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
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)
{
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;
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 1,
NULL, NULL);
@ -189,11 +187,11 @@ usb_request_status_t usb_vendor_request_set_antenna_enable(
if (stage == USB_TRANSFER_STAGE_SETUP) {
switch (endpoint->setup.value) {
case 0:
rf_path_set_antenna(0);
rf_path_set_antenna(&rf_path, 0);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
case 1:
rf_path_set_antenna(1);
rf_path_set_antenna(&rf_path, 1);
usb_transfer_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK;
default:

View File

@ -19,14 +19,7 @@
* 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 "max2837.h"
#include "rffc5071.h"
int main(void)
{
@ -38,21 +31,20 @@ int main(void)
enable_rf_power();
#endif
cpu_clock_init();
ssp1_init();
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LED1 on */
led_on(LED1);
ssp1_set_mode_max2837();
max2837_setup();
rffc5071_setup();
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */
max2837_setup(&max2837);
rffc5071_setup(&rffc5072);
led_on(LED2);
max2837_set_frequency(freq);
max2837_start();
max2837_tx();
gpio_set(PORT_LED1_3, (PIN_LED3)); /* LED3 on */
max2837_set_frequency(&max2837, freq);
max2837_start(&max2837);
max2837_tx(&max2837);
led_on(LED3);
while (1);
max2837_stop();
max2837_stop(&max2837);
return 0;
}

View File

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

View File

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

View File

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

View File

@ -19,13 +19,7 @@
* 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 "max2837.h"
int main(void)
{
@ -37,19 +31,18 @@ int main(void)
enable_rf_power();
#endif
cpu_clock_init();
ssp1_init();
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LED1 on */
led_on(LED1);
ssp1_set_mode_max2837();
max2837_setup();
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */
max2837_set_frequency(freq);
max2837_start();
max2837_tx();
gpio_set(PORT_LED1_3, (PIN_LED3)); /* LED3 on */
max2837_setup(&max2837);
led_on(LED2);
max2837_set_frequency(&max2837, freq);
max2837_start(&max2837);
max2837_tx(&max2837);
led_on(LED3);
while (1);
max2837_stop();
max2837_stop(&max2837);
return 0;
}

View File

@ -19,11 +19,7 @@
* Boston, MA 02110-1301, USA.
*/
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include "hackrf_core.h"
#include "w25q80bv.h"
int main(void)
{
@ -39,17 +35,19 @@ int main(void)
/* program test data to SPI flash */
for (i = 0; i < 515; i++)
buf[i] = (i * 3) & 0xFF;
w25q80bv_setup();
w25q80bv_chip_erase();
w25q80bv_program(790, 515, &buf[0]);
w25q80bv_setup(&w25q80bv);
w25q80bv_chip_erase(&w25q80bv);
w25q80bv_program(&w25q80bv, 790, 515, &buf[0]);
/* blink LED1 and LED3 */
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. */
__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. */
__asm__("nop");
}

View File

@ -19,10 +19,6 @@
* Boston, MA 02110-1301, USA.
*/
#include <libopencm3/lpc43xx/gpio.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/i2c.h>
#include "hackrf_core.h"
int main(void)
@ -35,23 +31,27 @@ int main(void)
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)
{
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LEDs on */
led_on(LED1);
for (i = 0; i < 2000000; i++) /* Wait a bit. */
__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. */
__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. */
__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. */
__asm__("nop");
}

View File

@ -19,9 +19,6 @@
* 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/cm3/systick.h>
#include <libopencm3/cm3/scs.h>
@ -139,19 +136,21 @@ int main(void)
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)
{
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LED1 on */
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */
gpio_set(PORT_LED1_3, (PIN_LED3)); /* LED3 on */
led_on(LED1);
led_on(LED2);
led_on(LED3);
sys_tick_wait_time_ms(500);
gpio_clear(PORT_LED1_3, (PIN_LED3)); /* LED3 off */
gpio_clear(PORT_LED1_3, (PIN_LED2)); /* LED2 off */
gpio_clear(PORT_LED1_3, (PIN_LED1)); /* LED1 off */
led_off(LED1);
led_off(LED2);
led_off(LED3);
sys_tick_wait_time_ms(500);
}

View File

@ -19,9 +19,6 @@
* 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/cm3/systick.h>
#include <libopencm3/cm3/scs.h>

View File

@ -19,9 +19,6 @@
* 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/cm3/systick.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_1000_nop_asm();
#define LED1_TOGGLE() (gpio_toggle(PORT_LED1_3, (PIN_LED1)))
#define LED1_TOGGLE() (led_toggle(LED1))
int main(void)
{
@ -152,7 +149,7 @@ int main(void)
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 */
LED1_TOGGLE();
@ -192,15 +189,15 @@ LED1_TOGGLE();
/* Test finished fast blink */
while (1)
{
gpio_set(PORT_LED1_3, (PIN_LED1)); /* LED1 on */
gpio_set(PORT_LED1_3, (PIN_LED2)); /* LED2 on */
gpio_set(PORT_LED1_3, (PIN_LED3)); /* LED3 on */
led_on(LED1);
led_on(LED2);
led_on(LED3);
sys_tick_wait_time_ms(250);
gpio_clear(PORT_LED1_3, (PIN_LED3)); /* LED3 off */
gpio_clear(PORT_LED1_3, (PIN_LED2)); /* LED2 off */
gpio_clear(PORT_LED1_3, (PIN_LED1)); /* LED1 off */
led_off(LED1);
led_off(LED2);
led_off(LED3);
sys_tick_wait_time_ms(250);
}