Merge branch 'hygiene_again' into develop

This commit is contained in:
Jared Boone
2019-03-20 14:28:12 -07:00
14 changed files with 742 additions and 603 deletions

View File

@ -60,17 +60,14 @@ static const hackrf_ui_t hackrf_ui_null = {
&hackrf_ui_set_antenna_bias_null, &hackrf_ui_set_antenna_bias_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

@ -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,37 @@ void cpu_clock_init(void)
#endif #endif
} }
void 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
/* Check for external clock input. */
if (si5351c_clkin_signal_valid(&clock_gen)) {
si5351c_set_clock_source(&clock_gen, PLL_SOURCE_CLKIN);
} 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)) {
si5351c_set_clock_source(&clock_gen, PLL_SOURCE_CLKIN);
return;
} else {
portapack_reference_oscillator(false);
}
}
#endif
/* No external or PortaPack clock was found. Use HackRF Si5351C crystal. */
si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL);
}
}
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

@ -294,6 +294,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);
void 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. */
@ -263,524 +256,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 +286,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;
@ -888,12 +358,9 @@ static void portapack_radio_path_redraw() {
portapack_draw_radio_path(radio_draw_list, ARRAY_SIZEOF(radio_draw_list)); portapack_draw_radio_path(radio_draw_list, ARRAY_SIZEOF(radio_draw_list));
} }
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_lcd_clear();
portapack_backlight(1);
} }
static void portapack_ui_set_frequency(uint64_t frequency) { static void portapack_ui_set_frequency(uint64_t frequency) {
@ -914,7 +381,7 @@ static void portapack_ui_set_frequency(uint64_t frequency) {
if( (i>=6) && (value == 0) ) { if( (i>=6) && (value == 0) ) {
/* 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);
} }
@ -1019,7 +486,7 @@ static void portapack_ui_set_antenna_bias(bool antenna_bias) {
(void)antenna_bias; (void)antenna_bias;
} }
static const hackrf_ui_t portapack_ui = { 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,
@ -1034,9 +501,9 @@ static const hackrf_ui_t portapack_ui = {
&portapack_ui_set_antenna_bias, &portapack_ui_set_antenna_bias,
}; };
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 */

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__*/

View File

@ -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"
@ -235,6 +236,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);