Merge pull request #645 from jboone/master

Sync up PortaPack UI changes.
This commit is contained in:
Michael Ossmann
2020-01-06 16:31:28 -07:00
committed by GitHub
23 changed files with 990 additions and 2828 deletions

View File

@ -26,16 +26,6 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
static const uint8_t cpld_xc2c64a_row_address[CPLD_XC2C64A_ROWS] = {
0x00, 0x40, 0x60, 0x20, 0x30, 0x70, 0x50, 0x10, 0x18, 0x58, 0x78, 0x38, 0x28, 0x68, 0x48, 0x08,
0x0c, 0x4c, 0x6c, 0x2c, 0x3c, 0x7c, 0x5c, 0x1c, 0x14, 0x54, 0x74, 0x34, 0x24, 0x64, 0x44, 0x04,
0x06, 0x46, 0x66, 0x26, 0x36, 0x76, 0x56, 0x16, 0x1e, 0x5e, 0x7e, 0x3e, 0x2e, 0x6e, 0x4e, 0x0e,
0x0a, 0x4a, 0x6a, 0x2a, 0x3a, 0x7a, 0x5a, 0x1a, 0x12, 0x52, 0x72, 0x32, 0x22, 0x62, 0x42, 0x02,
0x03, 0x43, 0x63, 0x23, 0x33, 0x73, 0x53, 0x13, 0x1b, 0x5b, 0x7b, 0x3b, 0x2b, 0x6b, 0x4b, 0x0b,
0x0f, 0x4f, 0x6f, 0x2f, 0x3f, 0x7f, 0x5f, 0x1f, 0x17, 0x57, 0x77, 0x37, 0x27, 0x67, 0x47, 0x07,
0x05, 0x45,
};
typedef enum { typedef enum {
CPLD_XC2C_IR_INTEST = 0b00000010, CPLD_XC2C_IR_INTEST = 0b00000010,
CPLD_XC2C_IR_BYPASS = 0b11111111, CPLD_XC2C_IR_BYPASS = 0b11111111,
@ -292,7 +282,7 @@ bool cpld_xc2c64a_jtag_checksum(
uint8_t dr[CPLD_XC2C64A_BYTES_IN_ROW]; uint8_t dr[CPLD_XC2C64A_BYTES_IN_ROW];
for(size_t row=0; row<CPLD_XC2C64A_ROWS; row++) { for(size_t row=0; row<CPLD_XC2C64A_ROWS; row++) {
const size_t address = cpld_xc2c64a_row_address[row]; const size_t address = cpld_hackrf_row_addresses.address[row];
cpld_xc2c64a_jtag_read_row(jtag, address, dr); cpld_xc2c64a_jtag_read_row(jtag, address, dr);
const size_t mask_index = verify->mask_index[row]; const size_t mask_index = verify->mask_index[row];
@ -388,7 +378,7 @@ void cpld_xc2c64a_jtag_sram_write(
cpld_xc2c_jtag_sram_write(jtag); cpld_xc2c_jtag_sram_write(jtag);
for(size_t row=0; row<CPLD_XC2C64A_ROWS; row++) { for(size_t row=0; row<CPLD_XC2C64A_ROWS; row++) {
const uint8_t address = cpld_xc2c64a_row_address[row]; const uint8_t address = cpld_hackrf_row_addresses.address[row];
cpld_xc2c64a_jtag_sram_write_row(jtag, address, &program->row[row].data[0]); cpld_xc2c64a_jtag_sram_write_row(jtag, address, &program->row[row].data[0]);
} }
@ -416,7 +406,7 @@ bool cpld_xc2c64a_jtag_sram_verify(
const size_t mask_index = (data_row >= 0) ? verify->mask_index[data_row] : 0; const size_t mask_index = (data_row >= 0) ? verify->mask_index[data_row] : 0;
const uint8_t* const expected = (data_row >= 0) ? &program->row[data_row].data[0] : NULL; const uint8_t* const expected = (data_row >= 0) ? &program->row[data_row].data[0] : NULL;
const uint8_t* const mask = (data_row >= 0) ? &verify->mask[mask_index].value[0] : NULL; const uint8_t* const mask = (data_row >= 0) ? &verify->mask[mask_index].value[0] : NULL;
const uint8_t next_address = (address_row < CPLD_XC2C64A_ROWS) ? cpld_xc2c64a_row_address[address_row] : 0; const uint8_t next_address = (address_row < CPLD_XC2C64A_ROWS) ? cpld_hackrf_row_addresses.address[address_row] : 0;
matched &= cpld_xc2c64a_jtag_sram_compare_row(jtag, expected, mask, next_address); matched &= cpld_xc2c64a_jtag_sram_compare_row(jtag, expected, mask, next_address);
} }

View File

@ -49,6 +49,10 @@ typedef struct {
uint8_t mask_index[CPLD_XC2C64A_ROWS]; uint8_t mask_index[CPLD_XC2C64A_ROWS];
} cpld_xc2c64a_verify_t; } cpld_xc2c64a_verify_t;
typedef struct {
uint8_t address[CPLD_XC2C64A_ROWS];
} cpld_xc2c64a_row_addresses_t;
bool cpld_xc2c64a_jtag_checksum( bool cpld_xc2c64a_jtag_checksum(
const jtag_t* const jtag, const jtag_t* const jtag,
const cpld_xc2c64a_verify_t* const verify, const cpld_xc2c64a_verify_t* const verify,
@ -66,5 +70,6 @@ bool cpld_xc2c64a_jtag_sram_verify(
extern const cpld_xc2c64a_program_t cpld_hackrf_program_sram; extern const cpld_xc2c64a_program_t cpld_hackrf_program_sram;
extern const cpld_xc2c64a_verify_t cpld_hackrf_verify; extern const cpld_xc2c64a_verify_t cpld_hackrf_verify;
extern const cpld_xc2c64a_row_addresses_t cpld_hackrf_row_addresses;
#endif/*__CPLD_XC2C_H__*/ #endif/*__CPLD_XC2C_H__*/

View File

@ -41,6 +41,7 @@ void hackrf_ui_set_bb_tx_vga_gain_null(const uint32_t gain_db) { UNUSED(gain_db)
void hackrf_ui_set_first_if_frequency_null(const uint64_t frequency) { UNUSED(frequency); } void hackrf_ui_set_first_if_frequency_null(const uint64_t frequency) { UNUSED(frequency); }
void hackrf_ui_set_filter_null(const rf_path_filter_t filter) { UNUSED(filter); } void hackrf_ui_set_filter_null(const rf_path_filter_t filter) { UNUSED(filter); }
void hackrf_ui_set_antenna_bias_null(bool antenna_bias) { UNUSED(antenna_bias); } void hackrf_ui_set_antenna_bias_null(bool antenna_bias) { UNUSED(antenna_bias); }
void hackrf_ui_set_clock_source_null(clock_source_t source) { UNUSED(source); }
/* Null UI function table, used if there's no hardware UI detected. Eliminates the /* Null UI function table, used if there's no hardware UI detected. Eliminates the
* need to check for null UI before calling a function in the table. * need to check for null UI before calling a function in the table.
@ -58,19 +59,17 @@ static const hackrf_ui_t hackrf_ui_null = {
&hackrf_ui_set_first_if_frequency_null, &hackrf_ui_set_first_if_frequency_null,
&hackrf_ui_set_filter_null, &hackrf_ui_set_filter_null,
&hackrf_ui_set_antenna_bias_null, &hackrf_ui_set_antenna_bias_null,
&hackrf_ui_set_clock_source_null,
}; };
const hackrf_ui_t* portapack_detect(void) __attribute__((weak));
const hackrf_ui_t* rad1o_ui_setup(void) __attribute__((weak));
static const hackrf_ui_t* ui = NULL; static const hackrf_ui_t* ui = NULL;
const hackrf_ui_t* hackrf_ui(void) { const hackrf_ui_t* hackrf_ui(void) {
/* Detect on first use. If no UI hardware is detected, use a stub function table. */ /* Detect on first use. If no UI hardware is detected, use a stub function table. */
if( ui == NULL ) { if( ui == NULL ) {
#ifdef HACKRF_ONE #ifdef HACKRF_ONE
if( portapack_detect ) { if( portapack_hackrf_ui_init ) {
ui = portapack_detect(); ui = portapack_hackrf_ui_init();
} }
#endif #endif
#ifdef RAD1O #ifdef RAD1O

View File

@ -22,7 +22,7 @@
#ifndef HACKRF_UI_H #ifndef HACKRF_UI_H
#define HACKRF_UI_H #define HACKRF_UI_H
#include <rf_path.h> #include <hackrf_core.h>
#include <stdint.h> #include <stdint.h>
typedef void (*hackrf_ui_init_fn)(void); typedef void (*hackrf_ui_init_fn)(void);
@ -37,6 +37,7 @@ typedef void (*hackrf_ui_set_bb_tx_vga_gain_fn)(const uint32_t gain_db);
typedef void (*hackrf_ui_set_first_if_frequency_fn)(const uint64_t frequency); typedef void (*hackrf_ui_set_first_if_frequency_fn)(const uint64_t frequency);
typedef void (*hackrf_ui_set_filter_fn)(const rf_path_filter_t filter); typedef void (*hackrf_ui_set_filter_fn)(const rf_path_filter_t filter);
typedef void (*hackrf_ui_set_antenna_bias_fn)(bool antenna_bias); typedef void (*hackrf_ui_set_antenna_bias_fn)(bool antenna_bias);
typedef void (*hackrf_ui_set_clock_source_fn)(clock_source_t source);
typedef struct { typedef struct {
hackrf_ui_init_fn init; hackrf_ui_init_fn init;
@ -51,6 +52,7 @@ typedef struct {
hackrf_ui_set_first_if_frequency_fn set_first_if_frequency; hackrf_ui_set_first_if_frequency_fn set_first_if_frequency;
hackrf_ui_set_filter_fn set_filter; hackrf_ui_set_filter_fn set_filter;
hackrf_ui_set_antenna_bias_fn set_antenna_bias; hackrf_ui_set_antenna_bias_fn set_antenna_bias;
hackrf_ui_set_clock_source_fn set_clock_source;
} hackrf_ui_t; } hackrf_ui_t;
/* TODO: Lame hack to know that PortaPack was detected. /* TODO: Lame hack to know that PortaPack was detected.

View File

@ -39,6 +39,10 @@
#include <libopencm3/lpc43xx/scu.h> #include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/ssp.h> #include <libopencm3/lpc43xx/ssp.h>
#ifdef HACKRF_ONE
#include "portapack.h"
#endif
#include "gpio_lpc.h" #include "gpio_lpc.h"
#define WAIT_CPU_CLOCK_INIT_DELAY (10000) #define WAIT_CPU_CLOCK_INIT_DELAY (10000)
@ -712,6 +716,41 @@ void cpu_clock_init(void)
#endif #endif
} }
clock_source_t activate_best_clock_source(void)
{
#ifdef HACKRF_ONE
/* Ensure PortaPack reference oscillator is off while checking for external clock input. */
if( portapack_reference_oscillator && portapack()) {
portapack_reference_oscillator(false);
}
#endif
clock_source_t source = CLOCK_SOURCE_HACKRF;
/* Check for external clock input. */
if (si5351c_clkin_signal_valid(&clock_gen)) {
source = CLOCK_SOURCE_EXTERNAL;
} else {
#ifdef HACKRF_ONE
/* Enable PortaPack reference oscillator (if present), and check for valid clock. */
if( portapack_reference_oscillator && portapack() ) {
portapack_reference_oscillator(true);
delay(510000); /* loop iterations @ 204MHz for >10ms for oscillator to enable. */
if (si5351c_clkin_signal_valid(&clock_gen)) {
source = CLOCK_SOURCE_PORTAPACK;
} else {
portapack_reference_oscillator(false);
}
}
#endif
/* No external or PortaPack clock was found. Use HackRF Si5351C crystal. */
}
si5351c_set_clock_source(&clock_gen, (source == CLOCK_SOURCE_HACKRF) ? PLL_SOURCE_XTAL : PLL_SOURCE_CLKIN);
hackrf_ui()->set_clock_source(source);
return source;
}
void ssp1_set_mode_max2837(void) void ssp1_set_mode_max2837(void)
{ {
spi_bus_start(max2837.bus, &ssp_config_max2837); spi_bus_start(max2837.bus, &ssp_config_max2837);

View File

@ -264,6 +264,12 @@ typedef enum {
HW_SYNC_MODE_ON = 1, HW_SYNC_MODE_ON = 1,
} hw_sync_mode_t; } hw_sync_mode_t;
typedef enum {
CLOCK_SOURCE_HACKRF = 0,
CLOCK_SOURCE_EXTERNAL = 1,
CLOCK_SOURCE_PORTAPACK = 2,
} clock_source_t;
void delay(uint32_t duration); void delay(uint32_t duration);
/* TODO: Hide these configurations */ /* TODO: Hide these configurations */
@ -294,6 +300,8 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom);
bool sample_rate_set(const uint32_t sampling_rate_hz); bool sample_rate_set(const uint32_t sampling_rate_hz);
bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz); bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz);
clock_source_t activate_best_clock_source(void);
#if (defined HACKRF_ONE || defined RAD1O) #if (defined HACKRF_ONE || defined RAD1O)
void enable_rf_power(void); void enable_rf_power(void);
void disable_rf_power(void); void disable_rf_power(void);

577
firmware/common/portapack.c Normal file
View File

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

View File

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

View File

@ -22,7 +22,7 @@
#include "si5351c.h" #include "si5351c.h"
enum pll_sources active_clock_source; enum pll_sources active_clock_source = PLL_SOURCE_UNINITIALIZED;
/* write to single register */ /* write to single register */
void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val) void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val)
@ -239,25 +239,14 @@ void si5351c_set_int_mode(si5351c_driver_t* const drv, const uint_fast8_t ms_num
void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source) void si5351c_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source)
{ {
if( source != active_clock_source ) {
si5351c_configure_clock_control(drv, source); si5351c_configure_clock_control(drv, source);
active_clock_source = source; active_clock_source = source;
} }
}
void si5351c_activate_best_clock_source(si5351c_driver_t* const drv) bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv) {
{ return (si5351c_read_single(drv, 0) & SI5351C_LOS) == 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(drv, PLL_SOURCE_XTAL);
}
} else {
/* CLKIN detected */
if (active_clock_source == PLL_SOURCE_XTAL) {
si5351c_set_clock_source(drv, PLL_SOURCE_CLKIN);
}
}
} }
void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable) void si5351c_clkout_enable(si5351c_driver_t* const drv, uint8_t enable)

View File

@ -29,6 +29,7 @@ extern "C"
#endif #endif
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include "i2c_bus.h" #include "i2c_bus.h"
@ -59,6 +60,7 @@ extern "C"
#define SI5351C_LOS (1<<4) #define SI5351C_LOS (1<<4)
enum pll_sources { enum pll_sources {
PLL_SOURCE_UNINITIALIZED = -1,
PLL_SOURCE_XTAL = 0, PLL_SOURCE_XTAL = 0,
PLL_SOURCE_CLKIN = 1, PLL_SOURCE_CLKIN = 1,
}; };
@ -84,7 +86,7 @@ void si5351c_configure_clock_control(si5351c_driver_t* const drv, const enum pll
void si5351c_enable_clock_outputs(si5351c_driver_t* const drv); 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_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_set_clock_source(si5351c_driver_t* const drv, const enum pll_sources source);
void si5351c_activate_best_clock_source(si5351c_driver_t* const drv); bool si5351c_clkin_signal_valid(si5351c_driver_t* const drv);
void si5351c_write_single(si5351c_driver_t* const drv, uint8_t reg, uint8_t val); 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); uint8_t si5351c_read_single(si5351c_driver_t* const drv, uint8_t reg);

View File

@ -19,16 +19,9 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include "hackrf-ui.h"
#include "ui_portapack.h" #include "ui_portapack.h"
#include "hackrf_core.h" #include "portapack.h"
#include "gpio_lpc.h"
#include <libopencm3/lpc43xx/scu.h>
#include <stddef.h>
/* Pixel data within a font or bitmap byte is "reversed": LSB is left-most pixel. */ /* Pixel data within a font or bitmap byte is "reversed": LSB is left-most pixel. */
@ -225,6 +218,14 @@ static const ui_bitmap_t bitmap_mixer = {
{ 24, 24 }, bitmap_mixer_data { 24, 24 }, bitmap_mixer_data
}; };
static const uint8_t bitmap_oscillator_data[] = {
0x00, 0x7e, 0x00, 0xc0, 0xff, 0x03, 0xe0, 0x81, 0x07, 0x70, 0x00, 0x0e, 0x38, 0x00, 0x1c, 0x1c, 0x00, 0x38, 0x0e, 0x03, 0x70, 0x86, 0x07, 0x60, 0xc6, 0x0f, 0x60, 0xc3, 0x0c, 0xc0, 0xe3, 0x1c, 0xc0, 0x63, 0x18, 0xc6, 0x63, 0x18, 0xc6, 0x03, 0x38, 0xc7, 0x03, 0x30, 0xc3, 0x06, 0xf0, 0x63, 0x06, 0xe0, 0x61, 0x0e, 0xc0, 0x70, 0x1c, 0x00, 0x38, 0x38, 0x00, 0x1c, 0x70, 0x00, 0x0e, 0xe0, 0x81, 0x07, 0xc0, 0xff, 0x03, 0x00, 0x7e, 0x00
};
static const ui_bitmap_t bitmap_oscillator = {
{ 24, 24 }, bitmap_oscillator_data
};
static const uint8_t bitmap_wire_8_data[] = { static const uint8_t bitmap_wire_8_data[] = {
0xff, 0xff 0xff, 0xff
}; };
@ -241,12 +242,28 @@ static const ui_bitmap_t bitmap_wire_24 = {
{ 24, 24 }, bitmap_wire_24_data { 24, 24 }, bitmap_wire_24_data
}; };
static const uint8_t bitmap_waves_data[] = { static const uint8_t bitmap_blank_24_data[] = {
0x00, 0x03, 0x00, 0x03, 0x00, 0x06, 0x30, 0x06, 0x30, 0x06, 0x30, 0x06, 0x60, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x63, 0x0c, 0x60, 0x0c, 0x30, 0x06, 0x30, 0x06, 0x30, 0x06, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
__attribute__((unused)) static const ui_bitmap_t bitmap_waves = { static const ui_bitmap_t bitmap_blank_24 = {
{ 16, 20 }, bitmap_waves_data { 24, 24 }, bitmap_blank_24_data
};
static const uint8_t bitmap_waves_rx_data[] = {
0xc0, 0x00, 0x60, 0x00, 0x70, 0x06, 0x30, 0x07, 0x38, 0x03, 0x98, 0x33, 0x98, 0x39, 0x98, 0x19, 0xcc, 0x18, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xcc, 0x18, 0x98, 0x19, 0x98, 0x39, 0x98, 0x33, 0x38, 0x03, 0x30, 0x07, 0x70, 0x06, 0x60, 0x00, 0xc0, 0x00
};
static const ui_bitmap_t bitmap_waves_rx = {
{ 16, 24 }, bitmap_waves_rx_data
};
static const uint8_t bitmap_waves_tx_data[] = {
0x00, 0x03, 0x00, 0x06, 0x60, 0x0e, 0xe0, 0x0c, 0xc0, 0x1c, 0xcc, 0x19, 0x9c, 0x19, 0x98, 0x19, 0x18, 0x33, 0x30, 0x33, 0x30, 0x33, 0x30, 0x33, 0x30, 0x33, 0x30, 0x33, 0x30, 0x33, 0x18, 0x33, 0x98, 0x19, 0x9c, 0x19, 0xcc, 0x19, 0xc0, 0x1c, 0xe0, 0x0c, 0x60, 0x0e, 0x00, 0x06, 0x00, 0x03
};
static const ui_bitmap_t bitmap_waves_tx = {
{ 16, 24 }, bitmap_waves_tx_data
}; };
__attribute__((unused)) static ui_color_t portapack_color_rgb( __attribute__((unused)) static ui_color_t portapack_color_rgb(
@ -263,524 +280,6 @@ __attribute__((unused)) static ui_color_t portapack_color_rgb(
static const ui_color_t color_background = { 0x001f }; static const ui_color_t color_background = { 0x001f };
static const ui_color_t color_foreground = { 0xffff }; static const ui_color_t color_foreground = { 0xffff };
#define ARRAY_SIZEOF(x) (sizeof(x) / sizeof(x[0]))
static void portapack_sleep_milliseconds(const uint32_t milliseconds) {
/* NOTE: Naively assumes 204 MHz instruction cycle clock and five instructions per count */
delay(milliseconds * 40800);
}
static struct gpio_t gpio_io_stbx = GPIO(5, 0); /* P2_0 */
static struct gpio_t gpio_addr = GPIO(5, 1); /* P2_1 */
__attribute__((unused)) static struct gpio_t gpio_lcd_te = GPIO(5, 3); /* P2_3 */
__attribute__((unused)) static struct gpio_t gpio_unused = GPIO(5, 7); /* P2_8 */
static struct gpio_t gpio_lcd_rdx = GPIO(5, 4); /* P2_4 */
static struct gpio_t gpio_lcd_wrx = GPIO(1, 10); /* P2_9 */
static struct gpio_t gpio_dir = GPIO(1, 13); /* P2_13 */
typedef struct portapack_t {
gpio_t gpio_dir;
gpio_t gpio_lcd_rdx;
gpio_t gpio_lcd_wrx;
gpio_t gpio_io_stbx;
gpio_t gpio_addr;
gpio_port_t* const gpio_port_data;
uint8_t io_reg;
} portapack_t;
static portapack_t portapack = {
.gpio_dir = &gpio_dir,
.gpio_lcd_rdx = &gpio_lcd_rdx,
.gpio_lcd_wrx = &gpio_lcd_wrx,
.gpio_io_stbx = &gpio_io_stbx,
.gpio_addr = &gpio_addr,
.gpio_port_data = GPIO_LPC_PORT(3),
.io_reg = 0x03,
};
/* NOTE: Code below assumes the shift value is "8". */
#define GPIO_DATA_SHIFT (8)
static const uint32_t gpio_data_mask = 0xFFU << GPIO_DATA_SHIFT;
static void portapack_data_mask_set() {
portapack.gpio_port_data->mask = ~gpio_data_mask;
}
static void portapack_data_write_low(const uint32_t value) {
portapack.gpio_port_data->mpin = (value << GPIO_DATA_SHIFT);
}
static void portapack_data_write_high(const uint32_t value) {
/* NOTE: Assumes no other bits in the port are masked. */
/* NOTE: Assumes that bits 15 through 8 are masked. */
portapack.gpio_port_data->mpin = value;
}
static void portapack_dir_read() {
portapack.gpio_port_data->dir &= ~gpio_data_mask;
gpio_set(portapack.gpio_dir);
}
static void portapack_dir_write() {
gpio_clear(portapack.gpio_dir);
portapack.gpio_port_data->dir |= gpio_data_mask;
/* TODO: Manipulating DIR[3] makes me queasy. The RFFC5072 DATA pin
* is also on port 3, and switches direction periodically...
* Time to resort to bit-banding to enforce atomicity? But then, how
* to change direction on eight bits efficiently? Or do I care, since
* the PortaPack data bus shouldn't change direction too frequently?
*/
}
__attribute__((unused)) static void portapack_lcd_rd_assert() {
gpio_clear(portapack.gpio_lcd_rdx);
}
static void portapack_lcd_rd_deassert() {
gpio_set(portapack.gpio_lcd_rdx);
}
static void portapack_lcd_wr_assert() {
gpio_clear(portapack.gpio_lcd_wrx);
}
static void portapack_lcd_wr_deassert() {
gpio_set(portapack.gpio_lcd_wrx);
}
static void portapack_io_stb_assert() {
gpio_clear(portapack.gpio_io_stbx);
}
static void portapack_io_stb_deassert() {
gpio_set(portapack.gpio_io_stbx);
}
static void portapack_addr(const bool value) {
gpio_write(portapack.gpio_addr, value);
}
static void portapack_lcd_command(const uint32_t value) {
portapack_data_write_high(0); /* Drive high byte (with zero -- don't care) */
portapack_dir_write(); /* Turn around data bus, MCU->CPLD */
portapack_addr(0); /* Indicate command */
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_lcd_wr_assert(); /* Latch high byte */
portapack_data_write_low(value); /* Drive low byte (pass-through) */
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_lcd_wr_deassert(); /* Complete write operation */
portapack_addr(1); /* Set up for data phase (most likely after a command) */
}
static void portapack_lcd_write_data(const uint32_t value) {
// NOTE: Assumes and DIR=0 and ADDR=1 from command phase.
portapack_data_write_high(value); /* Drive high byte */
__asm__("nop");
portapack_lcd_wr_assert(); /* Latch high byte */
portapack_data_write_low(value); /* Drive low byte (pass-through) */
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_lcd_wr_deassert(); /* Complete write operation */
}
static void portapack_io_write(const bool address, const uint_fast16_t value) {
portapack_data_write_low(value);
portapack_dir_write();
portapack_addr(address);
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_io_stb_assert();
__asm__("nop");
__asm__("nop");
__asm__("nop");
portapack_io_stb_deassert();
}
static void portapack_lcd_data_write_command_and_data(
const uint_fast8_t command,
const uint8_t* data,
const size_t data_count
) {
portapack_lcd_command(command);
for(size_t i=0; i<data_count; i++) {
portapack_lcd_write_data(data[i]);
}
}
static void portapack_lcd_write_pixel(const ui_color_t pixel) {
portapack_lcd_write_data(pixel.v);
}
static void portapack_lcd_write_pixels_color(ui_color_t c, size_t n) {
while(n--) {
portapack_lcd_write_data(c.v);
}
}
static void portapack_backlight(const bool on) {
portapack.io_reg = (portapack.io_reg & 0x7f) | (on ? (1 << 7) : 0);
portapack_io_write(1, portapack.io_reg);
}
static void portapack_lcd_reset_state(const bool active) {
portapack.io_reg = (portapack.io_reg & 0xfe) | (active ? (1 << 0) : 0);
portapack_io_write(1, portapack.io_reg);
}
static void portapack_lcd_sleep_out() {
const uint8_t cmd_11[] = {};
portapack_lcd_data_write_command_and_data(0x11, cmd_11, ARRAY_SIZEOF(cmd_11));
// "It will be necessary to wait 120msec after sending Sleep Out
// command (when in Sleep In Mode) before Sleep In command can be
// sent."
portapack_sleep_milliseconds(120);
}
static void portapack_lcd_display_on() {
const uint8_t cmd_29[] = {};
portapack_lcd_data_write_command_and_data(0x29, cmd_29, ARRAY_SIZEOF(cmd_29));
}
static void portapack_lcd_wake() {
portapack_lcd_sleep_out();
portapack_lcd_display_on();
}
static bool jtag_pp_tck(const bool tms_value) {
gpio_write(jtag_cpld.gpio->gpio_pp_tms, tms_value);
// 8 ns TMS/TDI to TCK setup
__asm__("nop");
__asm__("nop");
__asm__("nop");
gpio_set(jtag_cpld.gpio->gpio_tck);
// 15 ns TCK to TMS/TDI hold time
// 20 ns TCK high time
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
gpio_clear(jtag_cpld.gpio->gpio_tck);
// 20 ns TCK low time
// 25 ns TCK falling edge to TDO valid
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
return gpio_read(jtag_cpld.gpio->gpio_pp_tdo);
}
static uint32_t jtag_pp_shift(const uint32_t tms_bits, const size_t count) {
uint32_t result = 0;
size_t bit_in_index = count - 1;
size_t bit_out_index = 0;
while(bit_out_index < count) {
const uint32_t tdo = jtag_pp_tck((tms_bits >> bit_in_index) & 1) & 1;
result |= (tdo << bit_out_index);
bit_in_index--;
bit_out_index++;
}
return result;
}
static uint32_t jtag_pp_idcode() {
cpld_jtag_take(&jtag_cpld);
/* TODO: Check if PortaPack TMS is floating or driven by an external device. */
gpio_output(jtag_cpld.gpio->gpio_pp_tms);
/* Test-Logic/Reset -> Run-Test/Idle -> Select-DR/Scan -> Capture-DR */
jtag_pp_shift(0b11111010, 8);
/* Shift-DR */
const uint32_t idcode = jtag_pp_shift(0, 32);
/* Exit1-DR -> Update-DR -> Run-Test/Idle -> ... -> Test-Logic/Reset */
jtag_pp_shift(0b11011111, 8);
cpld_jtag_release(&jtag_cpld);
return idcode;
}
static void portapack_if_init() {
portapack_data_mask_set();
portapack_data_write_high(0);
portapack_dir_read();
portapack_lcd_rd_deassert();
portapack_lcd_wr_deassert();
portapack_io_stb_deassert();
portapack_addr(0);
gpio_output(portapack.gpio_dir);
gpio_output(portapack.gpio_lcd_rdx);
gpio_output(portapack.gpio_lcd_wrx);
gpio_output(portapack.gpio_io_stbx);
gpio_output(portapack.gpio_addr);
/* gpio_input(portapack.gpio_rot_a); */
/* gpio_input(portapack.gpio_rot_b); */
scu_pinmux(SCU_PINMUX_PP_D0, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D1, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D2, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D3, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D4, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D5, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D6, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_D7, SCU_CONF_FUNCTION0 | SCU_GPIO_PDN);
scu_pinmux(SCU_PINMUX_PP_DIR, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_PP_LCD_RDX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_PP_LCD_WRX, SCU_CONF_FUNCTION0 | SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_PP_IO_STBX, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL);
scu_pinmux(SCU_PINMUX_PP_ADDR, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL);
/* scu_pinmux(SCU_PINMUX_PP_LCD_TE, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */
/* scu_pinmux(SCU_PINMUX_PP_UNUSED, SCU_CONF_FUNCTION4 | SCU_GPIO_NOPULL); */
}
static void portapack_lcd_reset() {
portapack_lcd_reset_state(false);
portapack_sleep_milliseconds(1);
portapack_lcd_reset_state(true);
portapack_sleep_milliseconds(10);
portapack_lcd_reset_state(false);
portapack_sleep_milliseconds(120);
}
static void portapack_lcd_init() {
// LCDs are configured for IM[2:0] = 001
// 8080-I system, 16-bit parallel bus
//
// 0x3a: DBI[2:0] = 101
// MDT[1:0] = XX (if not in 18-bit mode, right?)
// Power control B
// 0
// PCEQ=1, DRV_ena=0, Power control=3
const uint8_t cmd_cf[] = { 0x00, 0xD9, 0x30 };
portapack_lcd_data_write_command_and_data(0xCF, cmd_cf, ARRAY_SIZEOF(cmd_cf));
// Power on sequence control
const uint8_t cmd_ed[] = { 0x64, 0x03, 0x12, 0x81 };
portapack_lcd_data_write_command_and_data(0xED, cmd_ed, ARRAY_SIZEOF(cmd_ed));
// Driver timing control A
const uint8_t cmd_e8[] = { 0x85, 0x10, 0x78 };
portapack_lcd_data_write_command_and_data(0xE8, cmd_e8, ARRAY_SIZEOF(cmd_e8));
// Power control A
const uint8_t cmd_cb[] = { 0x39, 0x2C, 0x00, 0x34, 0x02 };
portapack_lcd_data_write_command_and_data(0xCB, cmd_cb, ARRAY_SIZEOF(cmd_cb));
// Pump ratio control
const uint8_t cmd_f7[] = { 0x20 };
portapack_lcd_data_write_command_and_data(0xF7, cmd_f7, ARRAY_SIZEOF(cmd_f7));
// Driver timing control B
const uint8_t cmd_ea[] = { 0x00, 0x00 };
portapack_lcd_data_write_command_and_data(0xEA, cmd_ea, ARRAY_SIZEOF(cmd_ea));
const uint8_t cmd_b1[] = { 0x00, 0x1B };
portapack_lcd_data_write_command_and_data(0xB1, cmd_b1, ARRAY_SIZEOF(cmd_b1));
// Blanking Porch Control
// VFP = 0b0000010 = 2 (number of HSYNC of vertical front porch)
// VBP = 0b0000010 = 2 (number of HSYNC of vertical back porch)
// HFP = 0b0001010 = 10 (number of DOTCLOCK of horizontal front porch)
// HBP = 0b0010100 = 20 (number of DOTCLOCK of horizontal back porch)
const uint8_t cmd_b5[] = { 0x02, 0x02, 0x0a, 0x14 };
portapack_lcd_data_write_command_and_data(0xB5, cmd_b5, ARRAY_SIZEOF(cmd_b5));
// Display Function Control
// PT[1:0] = 0b10
// PTG[1:0] = 0b10
// ISC[3:0] = 0b0010 (scan cycle interval of gate driver: 5 frames)
// SM = 0 (gate driver pin arrangement in combination with GS)
// SS = 1 (source output scan direction S720 -> S1)
// GS = 0 (gate output scan direction G1 -> G320)
// REV = 1 (normally white)
// NL = 0b100111 (default)
// PCDIV = 0b000000 (default?)
const uint8_t cmd_b6[] = { 0x0A, 0xA2, 0x27, 0x00 };
portapack_lcd_data_write_command_and_data(0xB6, cmd_b6, ARRAY_SIZEOF(cmd_b6));
// Power Control 1
//VRH[5:0]
const uint8_t cmd_c0[] = { 0x1B };
portapack_lcd_data_write_command_and_data(0xC0, cmd_c0, ARRAY_SIZEOF(cmd_c0));
// Power Control 2
//SAP[2:0];BT[3:0]
const uint8_t cmd_c1[] = { 0x12 };
portapack_lcd_data_write_command_and_data(0xC1, cmd_c1, ARRAY_SIZEOF(cmd_c1));
// VCOM Control 1
const uint8_t cmd_c5[] = { 0x32, 0x3C };
portapack_lcd_data_write_command_and_data(0xC5, cmd_c5, ARRAY_SIZEOF(cmd_c5));
// VCOM Control 2
const uint8_t cmd_c7[] = { 0x9B };
portapack_lcd_data_write_command_and_data(0xC7, cmd_c7, ARRAY_SIZEOF(cmd_c7));
// Memory Access Control
// Invert X and Y memory access order, so upper-left of
// screen is (0,0) when writing to display.
const uint8_t cmd_36[] = {
(1 << 7) | // MY=1
(1 << 6) | // MX=1
(0 << 5) | // MV=0
(1 << 4) | // ML=1: reverse vertical refresh to simplify scrolling logic
(1 << 3) // BGR=1: For Kingtech LCD, BGR filter.
};
portapack_lcd_data_write_command_and_data(0x36, cmd_36, ARRAY_SIZEOF(cmd_36));
// COLMOD: Pixel Format Set
// DPI=101 (16 bits/pixel), DBI=101 (16 bits/pixel)
const uint8_t cmd_3a[] = { 0x55 };
portapack_lcd_data_write_command_and_data(0x3A, cmd_3a, ARRAY_SIZEOF(cmd_3a));
//portapack_lcd_data_write_command_and_data(0xF6, { 0x01, 0x30 });
// WEMODE=1 (reset column and page number on overflow)
// MDT[1:0]
// EPF[1:0]=00 (use channel MSB for LSB)
// RIM=0 (If COLMOD[6:4]=101 (65k color), 16-bit RGB interface (1 transfer/pixel))
// RM=0 (system interface/VSYNC interface)
// DM[1:0]=00 (internal clock operation)
// ENDIAN=0 (doesn't matter with 16-bit interface)
const uint8_t cmd_f6[] = { 0x01, 0x30, 0x00 };
portapack_lcd_data_write_command_and_data(0xF6, cmd_f6, ARRAY_SIZEOF(cmd_f6));
// 3Gamma Function Disable
const uint8_t cmd_f2[] = { 0x00 };
portapack_lcd_data_write_command_and_data(0xF2, cmd_f2, ARRAY_SIZEOF(cmd_f2));
// Gamma curve selected
const uint8_t cmd_26[] = { 0x01 };
portapack_lcd_data_write_command_and_data(0x26, cmd_26, ARRAY_SIZEOF(cmd_26));
// Set Gamma
const uint8_t cmd_e0[] = {
0x0F, 0x1D, 0x19, 0x0E, 0x10, 0x07, 0x4C, 0x63,
0x3F, 0x03, 0x0D, 0x00, 0x26, 0x24, 0x04
};
portapack_lcd_data_write_command_and_data(0xE0, cmd_e0, ARRAY_SIZEOF(cmd_e0));
// Set Gamma
const uint8_t cmd_e1[] = {
0x00, 0x1C, 0x1F, 0x02, 0x0F, 0x03, 0x35, 0x25,
0x47, 0x04, 0x0C, 0x0B, 0x29, 0x2F, 0x05
};
portapack_lcd_data_write_command_and_data(0xE1, cmd_e1, ARRAY_SIZEOF(cmd_e1));
portapack_lcd_wake();
// Turn on Tearing Effect Line (TE) output signal.
const uint8_t cmd_35[] = { 0b00000000 };
portapack_lcd_data_write_command_and_data(0x35, cmd_35, ARRAY_SIZEOF(cmd_35));
}
static void portapack_lcd_ramwr_start() {
const uint8_t cmd_2c[] = {};
portapack_lcd_data_write_command_and_data(0x2c, cmd_2c, ARRAY_SIZEOF(cmd_2c));
}
static void portapack_lcd_set(const uint_fast8_t command, const uint_fast16_t start, const uint_fast16_t end) {
const uint8_t data[] = {
(start >> 8), (start & 0xff),
(end >> 8), (end & 0xff)
};
portapack_lcd_data_write_command_and_data(command, data, ARRAY_SIZEOF(data));
}
static void portapack_lcd_caset(const uint_fast16_t start_column, uint_fast16_t end_column) {
portapack_lcd_set(0x2a, start_column, end_column);
}
static void portapack_lcd_paset(const uint_fast16_t start_page, const uint_fast16_t end_page) {
portapack_lcd_set(0x2b, start_page, end_page);
}
static void portapack_lcd_start_ram_write(
ui_rect_t rect
) {
portapack_lcd_caset(rect.point.x, rect.point.x + rect.size.width - 1);
portapack_lcd_paset(rect.point.y, rect.point.y + rect.size.height - 1);
portapack_lcd_ramwr_start();
}
static void portapack_lcd_fill_rectangle(
ui_rect_t rect,
ui_color_t color
) {
portapack_lcd_start_ram_write(rect);
portapack_lcd_write_pixels_color(color, rect.size.width * rect.size.height);
}
static void portapack_draw_bitmap(
const ui_point_t point,
const ui_bitmap_t bitmap,
const ui_color_t foreground,
const ui_color_t background
) {
const ui_rect_t rect = {
.point = point,
.size = bitmap.size
};
portapack_lcd_start_ram_write(rect);
const size_t count = bitmap.size.width * bitmap.size.height;
for(size_t i=0; i<count; i++) {
const uint8_t pixel = bitmap.data[i >> 3] & (1U << (i & 0x7));
portapack_lcd_write_pixel(pixel ? foreground : background);
}
}
static ui_bitmap_t portapack_font_glyph(
const ui_font_t* const font,
const char c
) {
if( c >= font->c_start ) {
const uint_fast8_t index = c - font->c_start;
if( index < font->c_count ) {
const ui_bitmap_t bitmap = {
.size = font->glyph_size,
.data = &font->data[index * font->data_stride]
};
return bitmap;
}
}
const ui_bitmap_t bitmap = {
.size = font->glyph_size,
.data = font->data,
};
return bitmap;
}
static ui_point_t portapack_lcd_draw_int(const ui_point_t point, uint64_t value, size_t field_width) { static ui_point_t portapack_lcd_draw_int(const ui_point_t point, uint64_t value, size_t field_width) {
const ui_point_t point_done = { const ui_point_t point_done = {
.x = point.x + font_fixed_8x16.glyph_size.width * field_width, .x = point.x + font_fixed_8x16.glyph_size.width * field_width,
@ -811,11 +310,6 @@ static ui_point_t portapack_lcd_draw_string(ui_point_t point, const char* s) {
return point; return point;
} }
static void portapack_lcd_clear() {
const ui_rect_t rect_screen = { { 0, 0 }, { 240, 320 } };
portapack_lcd_fill_rectangle(rect_screen, color_background);
}
typedef struct draw_list_t { typedef struct draw_list_t {
const ui_bitmap_t* bitmap; const ui_bitmap_t* bitmap;
const ui_point_t point; const ui_point_t point;
@ -824,7 +318,7 @@ typedef struct draw_list_t {
static draw_list_t radio_draw_list[] = { static draw_list_t radio_draw_list[] = {
{ &bitmap_antenna, { 32, 64 } }, { &bitmap_antenna, { 32, 64 } },
{ &bitmap_wire_8, { 43, 88 } }, { &bitmap_wire_8, { 43, 88 } },
{ &bitmap_amp_rx, { 32, 96 } }, { &bitmap_wire_24, { 32, 96 } },
{ &bitmap_wire_8, { 43, 120 } }, { &bitmap_wire_8, { 43, 120 } },
{ &bitmap_filter_hp, { 32, 128 } }, { &bitmap_filter_hp, { 32, 128 } },
{ &bitmap_wire_8, { 43, 152 } }, { &bitmap_wire_8, { 43, 152 } },
@ -838,6 +332,8 @@ static draw_list_t radio_draw_list[] = {
{ &bitmap_wire_8, { 43, 280 } }, { &bitmap_wire_8, { 43, 280 } },
{ &bitmap_amp_rx, { 32, 288 } }, { &bitmap_amp_rx, { 32, 288 } },
{ &bitmap_wire_8, { 43, 312 } }, { &bitmap_wire_8, { 43, 312 } },
{ &bitmap_oscillator, { 208, 288 } },
{ &bitmap_blank_24, { 60, 60 } },
}; };
typedef enum { typedef enum {
@ -848,17 +344,28 @@ typedef enum {
RADIO_DRAW_LIST_ITEM_BB_LNA_AMP = 8, RADIO_DRAW_LIST_ITEM_BB_LNA_AMP = 8,
RADIO_DRAW_LIST_ITEM_BB_MIXER = 10, RADIO_DRAW_LIST_ITEM_BB_MIXER = 10,
RADIO_DRAW_LIST_ITEM_BB_FILTER = 12, RADIO_DRAW_LIST_ITEM_BB_FILTER = 12,
RADIO_DRAW_LIST_ITEM_BB_VGA_AMP = 14 RADIO_DRAW_LIST_ITEM_BB_VGA_AMP = 14,
RADIO_DRAW_LIST_ITEM_CLOCK = 16,
RADIO_DRAW_LIST_ITEM_WAVES = 17,
} radio_draw_list_item_t; } radio_draw_list_item_t;
static const uint8_t VALUES_X = 72; static ui_point_t portapack_ui_label_point(const radio_draw_list_item_t item) {
const uint8_t VALUES_X = 72;
ui_point_t point = { VALUES_X, radio_draw_list[item].point.y + 4 };
return point;
}
static ui_point_t portapack_ui_draw_db(ui_point_t point, const uint32_t db) { static ui_point_t portapack_ui_draw_string(const radio_draw_list_item_t item, const char* s) {
return portapack_lcd_draw_string(portapack_ui_label_point(item), s);
}
static ui_point_t portapack_ui_draw_db(const radio_draw_list_item_t item, const uint32_t db) {
ui_point_t point = portapack_ui_label_point(item);
point = portapack_lcd_draw_int(point, db, 2); point = portapack_lcd_draw_int(point, db, 2);
return portapack_lcd_draw_string(point, " dB"); return portapack_lcd_draw_string(point, " dB");
} }
static ui_point_t portapack_ui_draw_bw_mhz(ui_point_t point, const uint64_t hz) { static ui_point_t portapack_ui_draw_bw_mhz(const radio_draw_list_item_t item, const uint64_t hz) {
const uint32_t lsd = 1000000 / 100; const uint32_t lsd = 1000000 / 100;
const uint32_t round_offset = lsd / 2; const uint32_t round_offset = lsd / 2;
@ -866,18 +373,21 @@ static ui_point_t portapack_ui_draw_bw_mhz(ui_point_t point, const uint64_t hz)
const uint32_t mhz = hz_offset / 1000000; const uint32_t mhz = hz_offset / 1000000;
const uint32_t frac = hz_offset / lsd; const uint32_t frac = hz_offset / lsd;
ui_point_t point = portapack_ui_label_point(item);
point = portapack_lcd_draw_int(point, mhz, 2); point = portapack_lcd_draw_int(point, mhz, 2);
point = portapack_lcd_draw_string(point, "."); point = portapack_lcd_draw_string(point, ".");
point = portapack_lcd_draw_int(point, frac, 2); point = portapack_lcd_draw_int(point, frac, 2);
return portapack_lcd_draw_string(point, " MHz"); return portapack_lcd_draw_string(point, " MHz");
} }
static void portapack_draw_radio_path( static void portapack_draw_radio_path_item(const radio_draw_list_item_t item) {
const draw_list_t* const draw_list, portapack_draw_bitmap(radio_draw_list[item].point, *radio_draw_list[item].bitmap, color_foreground, color_background);
const size_t count }
) {
for( size_t i=0; i<count; i++ ) { static void portapack_radio_path_item_update(const radio_draw_list_item_t item, const ui_bitmap_t* const bitmap) {
portapack_draw_bitmap(draw_list[i].point, *draw_list[i].bitmap, color_foreground, color_background); if( bitmap != radio_draw_list[item].bitmap ) {
radio_draw_list[item].bitmap = bitmap;
portapack_draw_radio_path_item(item);
} }
} }
@ -885,41 +395,51 @@ static rf_path_direction_t portapack_direction = RF_PATH_DIRECTION_OFF;
static bool portapack_lna_on = false; static bool portapack_lna_on = false;
static void portapack_radio_path_redraw() { static void portapack_radio_path_redraw() {
portapack_draw_radio_path(radio_draw_list, ARRAY_SIZEOF(radio_draw_list)); for( size_t i=0; i<ARRAY_SIZEOF(radio_draw_list); i++ ) {
portapack_draw_radio_path_item(i);
}
} }
static void portapack_ui_init() { static void portapack_ui_init(void) {
portapack_if_init(); portapack_clear_display(color_background);
portapack_lcd_reset(); portapack_backlight(true);
portapack_lcd_init(); portapack_radio_path_redraw();
portapack_lcd_clear();
portapack_backlight(1);
} }
static void portapack_ui_set_frequency(uint64_t frequency) { static void portapack_ui_set_frequency(uint64_t frequency) {
static char last[10] = " ";
ui_point_t point = { 240 - 20, 16 }; ui_point_t point = { 240 - 20, 16 };
uint64_t value = frequency; uint64_t value = frequency;
char s[10];
for(int i=0; i<10; i++) { for(int i=0; i<10; i++) {
const char c = '0' + value % 10; const char c = '0' + value % 10;
s[i] = ((i>=6) && (value == 0)) ? ' ' : c;
value /= 10;
}
for(int i=0; i<10; i++) {
const char c = s[i];
const ui_font_t* const font = (i > 5) ? &font_fixed_24x19 : &font_fixed_16x14; const ui_font_t* const font = (i > 5) ? &font_fixed_24x19 : &font_fixed_16x14;
const ui_bitmap_t glyph = portapack_font_glyph(font, c); point.x -= font->glyph_size.width;
point.x -= glyph.size.width;
if( (i==3) || (i==6) || (i==9) ) { if( (i==3) || (i==6) || (i==9) ) {
point.x -= 4; point.x -= 4;
} }
if( (i>=6) && (value == 0) ) { if( c != last[i] ) {
const ui_bitmap_t glyph = portapack_font_glyph(font, c);
if( c == ' ' ) {
/* Blank out leading zeros. */ /* Blank out leading zeros. */
const ui_rect_t rect = { point, glyph.size }; const ui_rect_t rect = { point, glyph.size };
portapack_lcd_fill_rectangle(rect, color_background); portapack_fill_rectangle(rect, color_background);
} else { } else {
portapack_draw_bitmap(point, glyph, color_foreground, color_background); portapack_draw_bitmap(point, glyph, color_foreground, color_background);
} }
last[i] = c;
value /= 10; }
} }
} }
@ -935,51 +455,48 @@ static void portapack_ui_set_sample_rate(uint32_t sample_rate) {
static void portapack_ui_set_direction(const rf_path_direction_t direction) { static void portapack_ui_set_direction(const rf_path_direction_t direction) {
switch(direction) { switch(direction) {
case RF_PATH_DIRECTION_TX: case RF_PATH_DIRECTION_TX:
radio_draw_list[RADIO_DRAW_LIST_ITEM_RF_AMP].bitmap = portapack_lna_on ? &bitmap_amp_tx : &bitmap_wire_24; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_WAVES, &bitmap_waves_tx);
radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_LNA_AMP].bitmap = &bitmap_amp_tx; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_RF_AMP, portapack_lna_on ? &bitmap_amp_tx : &bitmap_wire_24);
radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_VGA_AMP].bitmap = &bitmap_wire_24; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, &bitmap_amp_tx);
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, &bitmap_wire_24);
portapack_ui_draw_string(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, " ");
break; break;
case RF_PATH_DIRECTION_RX: case RF_PATH_DIRECTION_RX:
radio_draw_list[RADIO_DRAW_LIST_ITEM_RF_AMP].bitmap = portapack_lna_on ? &bitmap_amp_rx : &bitmap_wire_24; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_WAVES, &bitmap_waves_rx);
radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_LNA_AMP].bitmap = &bitmap_amp_rx; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_RF_AMP, portapack_lna_on ? &bitmap_amp_rx : &bitmap_wire_24);
radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_VGA_AMP].bitmap = &bitmap_amp_rx; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, &bitmap_amp_rx);
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, &bitmap_amp_rx);
break; break;
case RF_PATH_DIRECTION_OFF: case RF_PATH_DIRECTION_OFF:
default: default:
portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_WAVES, &bitmap_blank_24);
break; break;
} }
portapack_radio_path_redraw();
portapack_direction = direction; portapack_direction = direction;
} }
static void portapack_ui_set_filter_bw(uint32_t bandwidth) { static void portapack_ui_set_filter_bw(uint32_t bandwidth) {
ui_point_t point = { VALUES_X, radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_FILTER].point.y + 4 }; portapack_ui_draw_bw_mhz(RADIO_DRAW_LIST_ITEM_BB_FILTER, bandwidth);
portapack_ui_draw_bw_mhz(point, bandwidth);
} }
static void portapack_ui_set_lna_power(bool lna_on) { static void portapack_ui_set_lna_power(bool lna_on) {
portapack_lna_on = lna_on; portapack_lna_on = lna_on;
radio_draw_list[RADIO_DRAW_LIST_ITEM_RF_AMP].bitmap = lna_on portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_RF_AMP, lna_on
? ((portapack_direction == RF_PATH_DIRECTION_TX) ? &bitmap_amp_tx : &bitmap_amp_rx) ? ((portapack_direction == RF_PATH_DIRECTION_TX) ? &bitmap_amp_tx : &bitmap_amp_rx)
: &bitmap_wire_24; : &bitmap_wire_24);
const char* const label = lna_on ? "14 dB" : " "; const char* const label = lna_on ? "14 dB" : " ";
ui_point_t point = { VALUES_X, radio_draw_list[RADIO_DRAW_LIST_ITEM_RF_AMP].point.y + 4 }; portapack_ui_draw_string(RADIO_DRAW_LIST_ITEM_RF_AMP, label);
portapack_lcd_draw_string(point, label);
portapack_radio_path_redraw();
} }
static void portapack_ui_set_bb_lna_gain(const uint32_t gain_db) { static void portapack_ui_set_bb_lna_gain(const uint32_t gain_db) {
ui_point_t point = { VALUES_X, radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_LNA_AMP].point.y + 4 }; portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, gain_db);
portapack_ui_draw_db(point, gain_db);
} }
static void portapack_ui_set_bb_vga_gain(const uint32_t gain_db) { static void portapack_ui_set_bb_vga_gain(const uint32_t gain_db) {
ui_point_t point = { VALUES_X, radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_VGA_AMP].point.y + 4 }; portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_VGA_AMP, gain_db);
portapack_ui_draw_db(point, gain_db);
} }
static void portapack_ui_set_bb_tx_vga_gain(const uint32_t gain_db) { static void portapack_ui_set_bb_tx_vga_gain(const uint32_t gain_db) {
@ -987,8 +504,7 @@ static void portapack_ui_set_bb_tx_vga_gain(const uint32_t gain_db) {
* According to the MAX2837 datasheet diagram, there is no baseband gain in the TX path. * According to the MAX2837 datasheet diagram, there is no baseband gain in the TX path.
* This gets called when the TX IF gain is changed. * This gets called when the TX IF gain is changed.
*/ */
ui_point_t point = { VALUES_X, radio_draw_list[RADIO_DRAW_LIST_ITEM_BB_LNA_AMP].point.y + 4 }; portapack_ui_draw_db(RADIO_DRAW_LIST_ITEM_BB_LNA_AMP, gain_db);
portapack_ui_draw_db(point, gain_db);
} }
static void portapack_ui_set_first_if_frequency(const uint64_t frequency) { static void portapack_ui_set_first_if_frequency(const uint64_t frequency) {
@ -996,30 +512,44 @@ static void portapack_ui_set_first_if_frequency(const uint64_t frequency) {
} }
static void portapack_ui_set_filter(const rf_path_filter_t filter) { static void portapack_ui_set_filter(const rf_path_filter_t filter) {
radio_draw_list[RADIO_DRAW_LIST_ITEM_RF_MIXER].bitmap = (filter == RF_PATH_FILTER_BYPASS) ? &bitmap_wire_24 : &bitmap_mixer; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_RF_MIXER, (filter == RF_PATH_FILTER_BYPASS) ? &bitmap_wire_24 : &bitmap_mixer);
switch(filter) { switch(filter) {
default: default:
radio_draw_list[RADIO_DRAW_LIST_ITEM_IMAGE_FILTER].bitmap = &bitmap_wire_24; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_IMAGE_FILTER, &bitmap_wire_24);
break; break;
case RF_PATH_FILTER_LOW_PASS: case RF_PATH_FILTER_LOW_PASS:
radio_draw_list[RADIO_DRAW_LIST_ITEM_IMAGE_FILTER].bitmap = &bitmap_filter_lp; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_IMAGE_FILTER, &bitmap_filter_lp);
break; break;
case RF_PATH_FILTER_HIGH_PASS: case RF_PATH_FILTER_HIGH_PASS:
radio_draw_list[RADIO_DRAW_LIST_ITEM_IMAGE_FILTER].bitmap = &bitmap_filter_hp; portapack_radio_path_item_update(RADIO_DRAW_LIST_ITEM_IMAGE_FILTER, &bitmap_filter_hp);
break; break;
} }
portapack_radio_path_redraw();
} }
static void portapack_ui_set_antenna_bias(bool antenna_bias) { static void portapack_ui_set_antenna_bias(bool antenna_bias) {
(void)antenna_bias; (void)antenna_bias;
} }
static const hackrf_ui_t portapack_ui = { static void portapack_ui_set_clock_source(clock_source_t source) {
ui_point_t label_point = radio_draw_list[RADIO_DRAW_LIST_ITEM_CLOCK].point;
label_point.x -= 0;
label_point.y -= 16;
const char* s = "HRF";
switch(source) {
case CLOCK_SOURCE_EXTERNAL: { s = "EXT"; break; }
case CLOCK_SOURCE_PORTAPACK: { s = "PPK"; break; }
default:
case CLOCK_SOURCE_HACKRF: { s = "HRF"; break; }
}
portapack_lcd_draw_string(label_point, s);
}
const hackrf_ui_t portapack_hackrf_ui = {
&portapack_ui_init, &portapack_ui_init,
&portapack_ui_set_frequency, &portapack_ui_set_frequency,
&portapack_ui_set_sample_rate, &portapack_ui_set_sample_rate,
@ -1032,11 +562,12 @@ static const hackrf_ui_t portapack_ui = {
&portapack_ui_set_first_if_frequency, &portapack_ui_set_first_if_frequency,
&portapack_ui_set_filter, &portapack_ui_set_filter,
&portapack_ui_set_antenna_bias, &portapack_ui_set_antenna_bias,
&portapack_ui_set_clock_source,
}; };
const hackrf_ui_t* portapack_detect(void) { const hackrf_ui_t* portapack_hackrf_ui_init() {
if( jtag_pp_idcode() == 0x020A50DD ) { if( portapack() ) {
return &portapack_ui; return &portapack_hackrf_ui;
} else { } else {
return NULL; return NULL;
} }

View File

@ -22,40 +22,8 @@
#ifndef __UI_PORTAPACK_H__ #ifndef __UI_PORTAPACK_H__
#define __UI_PORTAPACK_H__ #define __UI_PORTAPACK_H__
#include <stddef.h> #include "hackrf-ui.h"
typedef struct ui_color_t { const hackrf_ui_t* portapack_hackrf_ui_init() __attribute__((weak));
uint16_t v;
} ui_color_t;
typedef struct ui_point_t {
int16_t x;
int16_t y;
} ui_point_t;
typedef struct ui_size_t {
int16_t width;
int16_t height;
} ui_size_t;
typedef struct ui_rect_t {
ui_point_t point;
ui_size_t size;
} ui_rect_t;
typedef struct ui_bitmap_t {
ui_size_t size;
const uint8_t* const data;
} ui_bitmap_t;
typedef struct ui_font_t {
const ui_size_t glyph_size;
const uint8_t* const data;
char c_start;
size_t c_count;
size_t data_stride;
} ui_font_t;
const hackrf_ui_t* portapack_detect(void);
#endif/*__UI_PORTAPACK_H__*/ #endif/*__UI_PORTAPACK_H__*/

View File

@ -19,7 +19,6 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include "hackrf-ui.h"
#include "ui_rad1o.h" #include "ui_rad1o.h"
/* Weak functions from rad1o app */ /* Weak functions from rad1o app */
@ -35,6 +34,7 @@ void hackrf_ui_setBBTXVGAGain(const uint32_t gain_db) __attribute__((weak));
void hackrf_ui_setFirstIFFrequency(const uint64_t freq) __attribute__((weak)); void hackrf_ui_setFirstIFFrequency(const uint64_t freq) __attribute__((weak));
void hackrf_ui_setFilter(const rf_path_filter_t filter) __attribute__((weak)); void hackrf_ui_setFilter(const rf_path_filter_t filter) __attribute__((weak));
void hackrf_ui_setAntennaBias(bool antenna_bias) __attribute__((weak)); void hackrf_ui_setAntennaBias(bool antenna_bias) __attribute__((weak));
void hackrf_ui_setClockSource(clock_source_t source) __attribute__((weak));
static void rad1o_ui_init(void) { static void rad1o_ui_init(void) {
hackrf_ui_init(); hackrf_ui_init();
@ -84,6 +84,10 @@ static void rad1o_ui_set_antenna_bias(bool antenna_bias) {
hackrf_ui_setAntennaBias(antenna_bias); hackrf_ui_setAntennaBias(antenna_bias);
} }
static void rad1o_ui_set_clock_source(clock_source_t source) {
hackrf_ui_setClockSource(source);
}
static const hackrf_ui_t rad1o_ui = { static const hackrf_ui_t rad1o_ui = {
&rad1o_ui_init, &rad1o_ui_init,
&rad1o_ui_set_frequency, &rad1o_ui_set_frequency,
@ -97,6 +101,7 @@ static const hackrf_ui_t rad1o_ui = {
&rad1o_ui_set_first_if_frequency, &rad1o_ui_set_first_if_frequency,
&rad1o_ui_set_filter, &rad1o_ui_set_filter,
&rad1o_ui_set_antenna_bias, &rad1o_ui_set_antenna_bias,
&rad1o_ui_set_clock_source,
}; };
const hackrf_ui_t* rad1o_ui_setup(void) { const hackrf_ui_t* rad1o_ui_setup(void) {

View File

@ -22,6 +22,8 @@
#ifndef __UI_RAD1O_H__ #ifndef __UI_RAD1O_H__
#define __UI_RAD1O_H__ #define __UI_RAD1O_H__
const hackrf_ui_t* rad1o_ui_setup(void); #include "hackrf-ui.h"
const hackrf_ui_t* rad1o_ui_setup(void) __attribute__((weak));
#endif/*__UI_RAD1O_H__*/ #endif/*__UI_RAD1O_H__*/

File diff suppressed because it is too large Load Diff

View File

@ -82,7 +82,7 @@ SET(HACKRF_OPTS "-D${BOARD} -DLPC43XX -D${MCU_PARTNO} -DTX_ENABLE -D'VERSION_STR
SET(LDSCRIPT_M4 "-T${PATH_HACKRF_FIRMWARE_COMMON}/${MCU_PARTNO}_M4_memory.ld -Tlibopencm3_lpc43xx_rom_to_ram.ld -T${PATH_HACKRF_FIRMWARE_COMMON}/LPC43xx_M4_M0_image_from_text.ld") SET(LDSCRIPT_M4 "-T${PATH_HACKRF_FIRMWARE_COMMON}/${MCU_PARTNO}_M4_memory.ld -Tlibopencm3_lpc43xx_rom_to_ram.ld -T${PATH_HACKRF_FIRMWARE_COMMON}/LPC43xx_M4_M0_image_from_text.ld")
SET(LDSCRIPT_M4_DFU "-T${PATH_HACKRF_FIRMWARE_COMMON}/${MCU_PARTNO}_M4_memory.ld -Tlibopencm3_lpc43xx.ld -T${PATH_HACKRF_FIRMWARE_COMMON}/LPC43xx_M4_M0_image_from_text.ld") SET(LDSCRIPT_M4_RAM "-T${PATH_HACKRF_FIRMWARE_COMMON}/${MCU_PARTNO}_M4_memory.ld -Tlibopencm3_lpc43xx.ld -T${PATH_HACKRF_FIRMWARE_COMMON}/LPC43xx_M4_M0_image_from_text.ld")
SET(LDSCRIPT_M0 "-T${PATH_HACKRF_FIRMWARE_COMMON}/LPC43xx_M0_memory.ld -Tlibopencm3_lpc43xx_m0.ld") SET(LDSCRIPT_M0 "-T${PATH_HACKRF_FIRMWARE_COMMON}/LPC43xx_M0_memory.ld -Tlibopencm3_lpc43xx_m0.ld")
@ -103,14 +103,38 @@ SET(CFLAGS_M4 "-std=gnu99 ${CFLAGS_COMMON} ${CPUFLAGS_M4} -DLPC43XX_M4")
SET(CXXFLAGS_M4 "-std=gnu++0x ${CFLAGS_COMMON} ${CPUFLAGS_M4} -DLPC43XX_M4") SET(CXXFLAGS_M4 "-std=gnu++0x ${CFLAGS_COMMON} ${CPUFLAGS_M4} -DLPC43XX_M4")
SET(LDFLAGS_M4 "${LDFLAGS_COMMON} ${CPUFLAGS_M4} ${LDSCRIPT_M4} -Xlinker -Map=m4.map") SET(LDFLAGS_M4 "${LDFLAGS_COMMON} ${CPUFLAGS_M4} ${LDSCRIPT_M4} -Xlinker -Map=m4.map")
SET(CFLAGS_M4_DFU "-std=gnu99 ${CFLAGS_COMMON} ${CPUFLAGS_M4} -DLPC43XX_M4 -DDFU_MODE") SET(CFLAGS_M4_RAM "-std=gnu99 ${CFLAGS_COMMON} ${CPUFLAGS_M4} -DLPC43XX_M4")
SET(LDFLAGS_M4_DFU "${LDFLAGS_COMMON} ${CPUFLAGS_M4} ${LDSCRIPT_M4_DFU} -Xlinker -Map=m4.map") SET(LDFLAGS_M4_RAM "${LDFLAGS_COMMON} ${CPUFLAGS_M4} ${LDSCRIPT_M4_RAM} -Xlinker -Map=m4.map")
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
include_directories("${LIBOPENCM3}/include/") include_directories("${LIBOPENCM3}/include/")
include_directories("${PATH_HACKRF_FIRMWARE_COMMON}") include_directories("${PATH_HACKRF_FIRMWARE_COMMON}")
macro(DeclareTarget project_name variant_suffix cflags ldflags)
add_library(${project_name}${variant_suffix}_objects OBJECT ${SRC_M4} m0_bin.s)
set_target_properties(${project_name}${variant_suffix}_objects PROPERTIES COMPILE_FLAGS "${cflags}")
add_dependencies(${project_name}${variant_suffix}_objects ${project_name}_m0.bin)
add_executable(${project_name}${variant_suffix}.elf $<TARGET_OBJECTS:${project_name}${variant_suffix}_objects>)
add_dependencies(${project_name}${variant_suffix}.elf libopencm3_${project_name})
target_link_libraries(
${project_name}${variant_suffix}.elf
c
nosys
opencm3_lpc43xx
m
)
set_target_properties(${project_name}${variant_suffix}.elf PROPERTIES LINK_FLAGS "${ldflags}")
add_custom_target(
${project_name}${variant_suffix}.bin ALL
DEPENDS ${project_name}${variant_suffix}.elf
COMMAND ${CMAKE_OBJCOPY} -Obinary ${project_name}${variant_suffix}.elf ${project_name}${variant_suffix}.bin
)
endmacro()
macro(DeclareTargets) macro(DeclareTargets)
SET(SRC_M4 SET(SRC_M4
${SRC_M4} ${SRC_M4}
@ -178,52 +202,9 @@ macro(DeclareTargets)
COMMAND ${CMAKE_OBJCOPY} -Obinary ${PROJECT_NAME}_m0.elf ${PROJECT_NAME}_m0.bin COMMAND ${CMAKE_OBJCOPY} -Obinary ${PROJECT_NAME}_m0.elf ${PROJECT_NAME}_m0.bin
) )
# Object files to be linked for SPI flash versions DeclareTarget("${PROJECT_NAME}" "" "${CFLAGS_M4}" "${LDFLAGS_M4}")
add_library(${PROJECT_NAME}_objects OBJECT ${SRC_M4} m0_bin.s) DeclareTarget("${PROJECT_NAME}" "_ram" "${CFLAGS_M4_RAM}" "${LDFLAGS_M4_RAM}")
set_target_properties(${PROJECT_NAME}_objects PROPERTIES COMPILE_FLAGS "${CFLAGS_M4}") DeclareTarget("${PROJECT_NAME}" "_dfu" "${CFLAGS_M4_RAM} -DDFU_MODE" "${LDFLAGS_M4_RAM}")
add_dependencies(${PROJECT_NAME}_objects ${PROJECT_NAME}_m0.bin)
add_executable(${PROJECT_NAME}.elf $<TARGET_OBJECTS:${PROJECT_NAME}_objects>)
add_dependencies(${PROJECT_NAME}.elf libopencm3_${PROJECT_NAME})
target_link_libraries(
${PROJECT_NAME}.elf
c
nosys
opencm3_lpc43xx
m
)
set_target_properties(${PROJECT_NAME}.elf PROPERTIES LINK_FLAGS "${LDFLAGS_M4}")
add_custom_target(
${PROJECT_NAME}.bin ALL
DEPENDS ${PROJECT_NAME}.elf
COMMAND ${CMAKE_OBJCOPY} -Obinary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
)
# DFU - using a differnet LD script to run directly from RAM
# Object files to be linked for DFU flash versions
add_library(${PROJECT_NAME}_dfu_objects OBJECT ${SRC_M4} m0_bin.s)
set_target_properties(${PROJECT_NAME}_dfu_objects PROPERTIES COMPILE_FLAGS "${CFLAGS_M4_DFU}")
add_dependencies(${PROJECT_NAME}_dfu_objects ${PROJECT_NAME}_m0.bin)
add_executable(${PROJECT_NAME}_dfu.elf $<TARGET_OBJECTS:${PROJECT_NAME}_dfu_objects>)
add_dependencies(${PROJECT_NAME}_dfu.elf libopencm3_${PROJECT_NAME})
target_link_libraries(
${PROJECT_NAME}_dfu.elf
c
nosys
opencm3_lpc43xx
m
)
set_target_properties(${PROJECT_NAME}_dfu.elf PROPERTIES LINK_FLAGS "${LDFLAGS_M4_DFU}")
add_custom_target(
${PROJECT_NAME}_dfu.bin
DEPENDS ${PROJECT_NAME}_dfu.elf
COMMAND ${CMAKE_OBJCOPY} -Obinary ${PROJECT_NAME}_dfu.elf ${PROJECT_NAME}_dfu.bin
)
add_custom_target( add_custom_target(
${PROJECT_NAME}.dfu ${DFU_ALL} ${PROJECT_NAME}.dfu ${DFU_ALL}

View File

@ -27,7 +27,7 @@ include(../hackrf-common.cmake)
add_custom_command( add_custom_command(
OUTPUT ${PATH_HACKRF_CPLD_DATA_C} OUTPUT ${PATH_HACKRF_CPLD_DATA_C}
COMMAND ${PATH_CPLD_BITSTREAM_TOOL} --code ${PATH_HACKRF_CPLD_XSVF} >${PATH_HACKRF_CPLD_DATA_C} COMMAND ${PATH_CPLD_BITSTREAM_TOOL} --xsvf ${PATH_HACKRF_CPLD_XSVF} --hackrf-data ${PATH_HACKRF_CPLD_DATA_C}
DEPENDS ${PATH_CPLD_BITSTREAM_TOOL} ${PATH_HACKRF_CPLD_XSVF} DEPENDS ${PATH_CPLD_BITSTREAM_TOOL} ${PATH_HACKRF_CPLD_XSVF}
) )
@ -66,6 +66,7 @@ set(SRC_M4
if(BOARD STREQUAL "HACKRF_ONE") if(BOARD STREQUAL "HACKRF_ONE")
SET(SRC_M4 SET(SRC_M4
${SRC_M4} ${SRC_M4}
"${PATH_HACKRF_FIRMWARE_COMMON}/portapack.c"
"${PATH_HACKRF_FIRMWARE_COMMON}/ui_portapack.c" "${PATH_HACKRF_FIRMWARE_COMMON}/ui_portapack.c"
) )
endif() endif()

View File

@ -46,6 +46,7 @@
#include "usb_api_transceiver.h" #include "usb_api_transceiver.h"
#include "usb_bulk_buffer.h" #include "usb_bulk_buffer.h"
#include "cpld_xc2c.h" #include "cpld_xc2c.h"
#include "portapack.h"
#include "hackrf-ui.h" #include "hackrf-ui.h"
@ -191,6 +192,10 @@ int main(void) {
halt_and_flash(6000000); halt_and_flash(6000000);
} }
#ifdef HACKRF_ONE
portapack_init();
#endif
#ifndef DFU_MODE #ifndef DFU_MODE
usb_set_descriptor_by_serial_number(); usb_set_descriptor_by_serial_number();
#endif #endif

View File

@ -273,7 +273,7 @@ void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) { if( _transceiver_mode != TRANSCEIVER_MODE_OFF ) {
si5351c_activate_best_clock_source(&clock_gen); activate_best_clock_source();
hw_sync_enable(_hw_sync_mode); hw_sync_enable(_hw_sync_mode);

View File

@ -6,6 +6,7 @@ bits_of_address = 7
bits_of_data = 274 bits_of_data = 274
bytes_of_data = (bits_of_data + 7) // 8 bytes_of_data = (bits_of_data + 7) // 8
bits_in_program_row = bits_of_address + bits_of_data bits_in_program_row = bits_of_address + bits_of_data
address_sequence = (0x00, 0x40, 0x60, 0x20, 0x30, 0x70, 0x50, 0x10, 0x18, 0x58, 0x78, 0x38, 0x28, 0x68, 0x48, 0x08, 0x0c, 0x4c, 0x6c, 0x2c, 0x3c, 0x7c, 0x5c, 0x1c, 0x14, 0x54, 0x74, 0x34, 0x24, 0x64, 0x44, 0x04, 0x06, 0x46, 0x66, 0x26, 0x36, 0x76, 0x56, 0x16, 0x1e, 0x5e, 0x7e, 0x3e, 0x2e, 0x6e, 0x4e, 0x0e, 0x0a, 0x4a, 0x6a, 0x2a, 0x3a, 0x7a, 0x5a, 0x1a, 0x12, 0x52, 0x72, 0x32, 0x22, 0x62, 0x42, 0x02, 0x03, 0x43, 0x63, 0x23, 0x33, 0x73, 0x53, 0x13, 0x1b, 0x5b, 0x7b, 0x3b, 0x2b, 0x6b, 0x4b, 0x0b, 0x0f, 0x4f, 0x6f, 0x2f, 0x3f, 0x7f, 0x5f, 0x1f, 0x17, 0x57, 0x77, 0x37, 0x27, 0x67, 0x47, 0x07, 0x05, 0x45,)
def values_list_line_wrap(values): def values_list_line_wrap(values):
line_length = 16 line_length = 16
@ -102,8 +103,6 @@ def extract_programming_data(commands):
} }
def validate_programming_data(programming_data): def validate_programming_data(programming_data):
expected_address_sequence = (0x00, 0x40, 0x60, 0x20, 0x30, 0x70, 0x50, 0x10, 0x18, 0x58, 0x78, 0x38, 0x28, 0x68, 0x48, 0x08, 0x0c, 0x4c, 0x6c, 0x2c, 0x3c, 0x7c, 0x5c, 0x1c, 0x14, 0x54, 0x74, 0x34, 0x24, 0x64, 0x44, 0x04, 0x06, 0x46, 0x66, 0x26, 0x36, 0x76, 0x56, 0x16, 0x1e, 0x5e, 0x7e, 0x3e, 0x2e, 0x6e, 0x4e, 0x0e, 0x0a, 0x4a, 0x6a, 0x2a, 0x3a, 0x7a, 0x5a, 0x1a, 0x12, 0x52, 0x72, 0x32, 0x22, 0x62, 0x42, 0x02, 0x03, 0x43, 0x63, 0x23, 0x33, 0x73, 0x53, 0x13, 0x1b, 0x5b, 0x7b, 0x3b, 0x2b, 0x6b, 0x4b, 0x0b, 0x0f, 0x4f, 0x6f, 0x2f, 0x3f, 0x7f, 0x5f, 0x1f, 0x17, 0x57, 0x77, 0x37, 0x27, 0x67, 0x47, 0x07, 0x05, 0x45,)
# Validate program blocks: # Validate program blocks:
# There should be two extracted program blocks. The first contains the # There should be two extracted program blocks. The first contains the
@ -113,7 +112,7 @@ def validate_programming_data(programming_data):
# First program phase writes the bitstream to flash (or SRAM) with # First program phase writes the bitstream to flash (or SRAM) with
# special bit(s) not asserted, so the bitstream is not yet valid. # special bit(s) not asserted, so the bitstream is not yet valid.
assert(extract_addresses(programming_data['program'][0]) == expected_address_sequence) assert(extract_addresses(programming_data['program'][0]) == address_sequence)
# Second program phase updates a single row to finish the programming # Second program phase updates a single row to finish the programming
# process. # process.
@ -129,8 +128,8 @@ def validate_programming_data(programming_data):
assert(programming_data['verify'][0] == programming_data['verify'][1]) assert(programming_data['verify'][0] == programming_data['verify'][1])
# Check the row address order of the second verify block. # Check the row address order of the second verify block.
assert(extract_addresses(programming_data['verify'][0]) == expected_address_sequence) assert(extract_addresses(programming_data['verify'][0]) == address_sequence)
assert(extract_addresses(programming_data['verify'][1]) == expected_address_sequence) assert(extract_addresses(programming_data['verify'][1]) == address_sequence)
# Checks across programming and verification: # Checks across programming and verification:
@ -150,12 +149,13 @@ def make_sram_program(program_blocks):
import argparse import argparse
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
action_group = parser.add_mutually_exclusive_group(required=True) action_group = parser.add_argument_group(title='outputs')
action_group.add_argument('--checksum', action='store_true', help='Calculate bitstream read-back CRC32 value') action_group.add_argument('--checksum', action='store_true', help='Print bitstream verification CRC32 value')
action_group.add_argument('--code', action='store_true', help='Generate C code for bitstream loading/programming/verification') action_group.add_argument('--hackrf-data', type=str, help='C data file for HackRF bitstream loading/programming/verification')
action_group.add_argument('--portapack-data', type=str, help='C++ data file for PortaPack bitstream loading/programming/verification')
parser.add_argument('--crcmod', action='store_true', help='Use Python crcmod library instead of built-in CRC32 code') parser.add_argument('--crcmod', action='store_true', help='Use Python crcmod library instead of built-in CRC32 code')
parser.add_argument('--debug', action='store_true', help='Enable debug output') parser.add_argument('--debug', action='store_true', help='Enable debug output')
parser.add_argument('hackrf_xc2c_cpld_xsvf', type=str, help='HackRF Xilinx XC2C64A CPLD XSVF file containing erase/program/verify phases') parser.add_argument('--xsvf', required=True, type=str, help='HackRF Xilinx XC2C64A CPLD XSVF file containing erase/program/verify phases')
args = parser.parse_args() args = parser.parse_args()
####################################################################### #######################################################################
@ -163,7 +163,7 @@ args = parser.parse_args()
# against the CPLD. # against the CPLD.
####################################################################### #######################################################################
with open(args.hackrf_xc2c_cpld_xsvf, "rb") as f: with open(args.xsvf, "rb") as f:
from xsvf import XSVFParser from xsvf import XSVFParser
commands = XSVFParser().parse(f, debug=args.debug) commands = XSVFParser().parse(f, debug=args.debug)
@ -203,7 +203,7 @@ if args.checksum:
print('0x%s' % crc.hexdigest().lower()) print('0x%s' % crc.hexdigest().lower())
if args.code: if args.hackrf_data:
program_sram = make_sram_program(program_blocks) program_sram = make_sram_program(program_blocks)
verify_block = verify_blocks[1] verify_block = verify_blocks[1]
verify_masks = tuple(frozenset(extract_mask(verify_block))) verify_masks = tuple(frozenset(extract_mask(verify_block)))
@ -237,5 +237,42 @@ if args.code:
'\t}', '\t}',
'};', '};',
'', '',
'const cpld_xc2c64a_row_addresses_t cpld_hackrf_row_addresses = { {',
)) ))
print('\n'.join(result)) result.extend(['\t%s' % line for line in hex_lines(address_sequence)])
result.extend((
'} };',
'',
))
with open(args.hackrf_data, 'w') as f:
f.write('\n'.join(result))
if args.portapack_data:
program_sram = make_sram_program(program_blocks)
verify_block = verify_blocks[1]
verify_masks = extract_mask(verify_block)
result = []
result.extend((
'/*',
' * WARNING: Auto-generated file. Do not edit.',
'*/',
'#include "hackrf_cpld_data.hpp"',
'namespace hackrf {',
'namespace one {',
'namespace cpld {',
'const ::cpld::xilinx::XC2C64A::verify_blocks_t verify_blocks { {',
))
data_lines = [', '.join(['0x%02x' % n for n in row['data'].to_bytes(bytes_of_data, byteorder='big')]) for row in program_sram]
mask_lines = [', '.join(['0x%02x' % n for n in mask.to_bytes(bytes_of_data, byteorder='big')]) for mask in verify_masks]
lines = ['{ 0x%02x, { { %s } }, { { %s } } }' % data for data in zip(address_sequence, data_lines, mask_lines)]
result.extend('\t%s,' % line for line in lines)
result.extend((
'} };',
'} /* namespace hackrf */',
'} /* namespace one */',
'} /* namespace cpld */',
'',
))
with open(args.portapack_data, 'w') as f:
f.write('\n'.join(result))

View File

@ -126,6 +126,7 @@ int main(void)
} }
} }
#ifdef HACKRF_ISSUE_609_IS_FIXED
uint32_t cpld_crc = 0; uint32_t cpld_crc = 0;
result = hackrf_cpld_checksum(device, &cpld_crc); result = hackrf_cpld_checksum(device, &cpld_crc);
if ((result != HACKRF_SUCCESS) && (result != HACKRF_ERROR_USB_API_VERSION)) { if ((result != HACKRF_SUCCESS) && (result != HACKRF_ERROR_USB_API_VERSION)) {
@ -136,6 +137,7 @@ int main(void)
if(result == HACKRF_SUCCESS) { if(result == HACKRF_SUCCESS) {
printf("CPLD checksum: 0x%08x\n", cpld_crc); printf("CPLD checksum: 0x%08x\n", cpld_crc);
} }
#endif /* HACKRF_ISSUE_609_IS_FIXED */
result = hackrf_close(device); result = hackrf_close(device);
if (result != HACKRF_SUCCESS) { if (result != HACKRF_SUCCESS) {

View File

@ -2105,6 +2105,7 @@ int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device, const uint8_t addr
} }
} }
#ifdef HACKRF_ISSUE_609_IS_FIXED
int ADDCALL hackrf_cpld_checksum(hackrf_device* device, int ADDCALL hackrf_cpld_checksum(hackrf_device* device,
uint32_t* crc) uint32_t* crc)
{ {
@ -2133,6 +2134,7 @@ int ADDCALL hackrf_cpld_checksum(hackrf_device* device,
return HACKRF_SUCCESS; return HACKRF_SUCCESS;
} }
} }
#endif /* HACKRF_ISSUE_609_IS_FIXED */
#ifdef __cplusplus #ifdef __cplusplus
} // __cplusplus defined. } // __cplusplus defined.

View File

@ -254,9 +254,10 @@ extern ADDAPI int ADDCALL hackrf_set_clkout_enable(hackrf_device* device, const
extern ADDAPI int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device, extern ADDAPI int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device,
uint8_t address, uint8_t address,
uint16_t* test_result); uint16_t* test_result);
#ifdef HACKRF_ISSUE_609_IS_FIXED
extern ADDAPI int ADDCALL hackrf_cpld_checksum(hackrf_device* device, extern ADDAPI int ADDCALL hackrf_cpld_checksum(hackrf_device* device,
uint32_t* crc); uint32_t* crc);
#endif /* HACKRF_ISSUE_609_IS_FIXED */
#ifdef __cplusplus #ifdef __cplusplus
} // __cplusplus defined. } // __cplusplus defined.