operacake: add support for port switching using SCTimer
Based on Schuyler St. Leger's operacake-sctimer branch
This commit is contained in:

committed by
Mike Walters

parent
790b5d35cf
commit
9ee25ab48a
@ -691,7 +691,7 @@ void cpu_clock_init(void)
|
||||
CCU1_CLK_M4_LCD_CFG = 0;
|
||||
CCU1_CLK_M4_QEI_CFG = 0;
|
||||
CCU1_CLK_M4_RITIMER_CFG = 0;
|
||||
CCU1_CLK_M4_SCT_CFG = 0;
|
||||
// CCU1_CLK_M4_SCT_CFG = 0;
|
||||
CCU1_CLK_M4_SDIO_CFG = 0;
|
||||
CCU1_CLK_M4_SPIFI_CFG = 0;
|
||||
CCU1_CLK_M4_TIMER0_CFG = 0;
|
||||
|
216
firmware/common/operacake_sctimer.c
Normal file
216
firmware/common/operacake_sctimer.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2018 Schuyler St. Leger
|
||||
* Copyright 2021 Great Scott Gadgets
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "operacake_sctimer.h"
|
||||
|
||||
#include <hackrf_core.h>
|
||||
|
||||
#include <libopencm3/lpc43xx/sgpio.h>
|
||||
#include <libopencm3/lpc43xx/rgu.h>
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
#include <libopencm3/lpc43xx/gima.h>
|
||||
#include "sct.h"
|
||||
|
||||
|
||||
#define U1CTRL_SET SCT_OUT14_SET
|
||||
#define U1CTRL_CLR SCT_OUT14_CLR
|
||||
#define U2CTRL0_SET SCT_OUT13_SET
|
||||
#define U2CTRL0_CLR SCT_OUT13_CLR
|
||||
#define U2CTRL1_SET SCT_OUT12_SET
|
||||
#define U2CTRL1_CLR SCT_OUT12_CLR
|
||||
#define U3CTRL0_SET SCT_OUT11_SET
|
||||
#define U3CTRL0_CLR SCT_OUT11_CLR
|
||||
#define U3CTRL1_SET SCT_OUT8_SET
|
||||
#define U3CTRL1_CLR SCT_OUT8_CLR
|
||||
|
||||
static uint32_t default_output = 0;
|
||||
|
||||
/**
|
||||
* Configure the SCTimer to rotate the antennas with the Operacake in phase with
|
||||
* the sample clock. This will configure the SCTimer to output to the pins for
|
||||
* GPIO control of the Operacake, however the Operacake must be configured for
|
||||
* GPIO control. The timing is not set in this function.
|
||||
*
|
||||
* To trigger the antenna switching synchronously with the sample clock, the
|
||||
* SGPIO is configured to output its clock (f=2 * sample clock) to the SCTimer.
|
||||
*/
|
||||
void operacake_sctimer_init() {
|
||||
// We start by resetting the SCTimer
|
||||
RESET_CTRL1 = RESET_CTRL1_SCT_RST;
|
||||
|
||||
// Delay to allow reset sigal to be processed
|
||||
// The reset generator uses a 12MHz clock (IRC)
|
||||
// The difference between this and the core clock (CCLK)
|
||||
// determines this value (CCLK/IRC).
|
||||
// The value used here is a bit shorter than would be required, since
|
||||
// there are additional instructions that fill the time. If the duration of
|
||||
// the actions from here to the first access to the SCTimer is changed, then
|
||||
// this delay may need to be increased.
|
||||
delay(8);
|
||||
|
||||
|
||||
// Pin definitions for the HackRF
|
||||
// U2CTRL0
|
||||
scu_pinmux(P7_4, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
// U2CTRL1
|
||||
scu_pinmux(P7_5, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
// U3CTRL0
|
||||
scu_pinmux(P7_6, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
// U3CTRL1
|
||||
scu_pinmux(P7_7, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
// U1CTRL
|
||||
scu_pinmux(P7_0, SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
|
||||
|
||||
// Configure the SGPIO to output the clock (f=2 * sample clock) on pin 12
|
||||
SGPIO_OUT_MUX_CFG12 =
|
||||
SGPIO_OUT_MUX_CFG_P_OUT_CFG(0x08) | // clkout output mode
|
||||
SGPIO_OUT_MUX_CFG_P_OE_CFG(0); // gpio_oe
|
||||
SGPIO_GPIO_OENREG |= BIT12;
|
||||
|
||||
// Use the GIMA to connect the SGPIO clock to the SCTimer
|
||||
GIMA_CTIN_1_IN = 0x2 << 4; // Route SGPIO12 to SCTIN1
|
||||
|
||||
// We configure this register first, because the user manual says to
|
||||
SCT_CONFIG |= SCT_CONFIG_UNIFY_32_BIT
|
||||
| SCT_CONFIG_CLKMODE_PRESCALED_BUS_CLOCK
|
||||
| SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_1;
|
||||
|
||||
// Halt the SCTimer to enable it to be configured
|
||||
SCT_CTRL = SCT_CTRL_HALT_L(1);
|
||||
|
||||
// Prescaler - run at half the SGPIO clock (ie: at the sample clock)
|
||||
SCT_CTRL |= SCT_CTRL_PRE_L(1);
|
||||
|
||||
// Default to state 0, events disabled
|
||||
SCT_STATE = 0;
|
||||
|
||||
// Enable the SCTimer
|
||||
SCT_CTRL &= ~SCT_CTRL_HALT_L(1);
|
||||
}
|
||||
|
||||
static uint32_t operacake_sctimer_port_to_output(uint8_t port) {
|
||||
int bit0 = (port >> 0) & 1;
|
||||
int bit1 = (port >> 1) & 1;
|
||||
int bit2 = (port >> 2) & 1;
|
||||
|
||||
return (bit0 << 11) | (bit0 << 13) |
|
||||
(bit1 << 8) | (bit1 << 12) |
|
||||
(((~bit2)&1) << 14);
|
||||
}
|
||||
|
||||
void operacake_sctimer_enable(bool enable) {
|
||||
SCT_CTRL = SCT_CTRL_HALT_L(1);
|
||||
SCT_STATE = enable;
|
||||
SCT_CTRL &= ~SCT_CTRL_HALT_L(1);
|
||||
}
|
||||
|
||||
void operacake_sctimer_set_dwell_times(struct operacake_dwell_times *times, int n) {
|
||||
|
||||
SCT_CTRL = SCT_CTRL_HALT_L(1);
|
||||
|
||||
uint32_t counter = 0;
|
||||
uint32_t bit0_set = 0, bit0_clr = 0, bit1_set = 0, bit1_clr = 0, bit2_set = 0, bit2_clr = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
// Enable event i in state 1, set to match on match register i
|
||||
SCT_EVn_STATE(i) = SCT_EVn_STATE_STATEMSK1(1);
|
||||
SCT_EVn_CTRL(i) = SCT_EVn_CTRL_COMBMODE_MATCH | SCT_EVn_CTRL_MATCHSEL(i);
|
||||
|
||||
// Calculate the counter value to match on
|
||||
counter += times[i].dwell;
|
||||
|
||||
// Wrapping from SCT_LIMIT seems to add an extra cycle,
|
||||
// so we reduce the counter value for the first event.
|
||||
if (i == 0)
|
||||
counter -= 1;
|
||||
|
||||
SCT_MATCHn(i) = counter;
|
||||
SCT_MATCHRELn(i) = counter;
|
||||
|
||||
// The match event selects the *next* port, so retreive that here.
|
||||
int port;
|
||||
if (i == n - 1) {
|
||||
port = times[0].port;
|
||||
} else {
|
||||
port = times[i+1].port;
|
||||
}
|
||||
|
||||
int bit0 = (port >> 0) & 1;
|
||||
int bit1 = (port >> 1) & 1;
|
||||
int bit2 = (port >> 2) & 1;
|
||||
|
||||
// Find bits to set/clear on event i
|
||||
bit0_set |= SCT_OUTn_SETm( bit0, i);
|
||||
bit0_clr |= SCT_OUTn_CLRm(~bit0, i);
|
||||
|
||||
bit1_set |= SCT_OUTn_SETm( bit1, i);
|
||||
bit1_clr |= SCT_OUTn_CLRm(~bit1, i);
|
||||
|
||||
// (U1CTRL is inverted)
|
||||
bit2_set |= SCT_OUTn_SETm(~bit2, i);
|
||||
bit2_clr |= SCT_OUTn_CLRm( bit2, i);
|
||||
}
|
||||
|
||||
// Apply event set/clear mappings
|
||||
U2CTRL0_SET = bit0_set;
|
||||
U2CTRL0_CLR = bit0_clr;
|
||||
U3CTRL0_SET = bit0_set;
|
||||
U3CTRL0_CLR = bit0_clr;
|
||||
U2CTRL1_SET = bit1_set;
|
||||
U2CTRL1_CLR = bit1_clr;
|
||||
U3CTRL1_SET = bit1_set;
|
||||
U3CTRL1_CLR = bit1_clr;
|
||||
U1CTRL_SET = bit2_set;
|
||||
U1CTRL_CLR = bit2_clr;
|
||||
|
||||
// Set output pins to select the first port in the list
|
||||
default_output = operacake_sctimer_port_to_output(times[0].port);
|
||||
SCT_OUTPUT = default_output;
|
||||
|
||||
// Reset counter on final event
|
||||
SCT_LIMIT = (1 << (n-1));
|
||||
|
||||
SCT_CTRL &= ~SCT_CTRL_HALT_L(1);
|
||||
}
|
||||
|
||||
void operacake_sctimer_stop() {
|
||||
// Halt timer
|
||||
SCT_CTRL |= SCT_CTRL_HALT_L(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will reset the state of the SCTimer, but retains its configuration.
|
||||
* This reset will return the selected antenna to 1 and samesided. This is
|
||||
* called by set_transceiver_mode so the HackRF starts capturing with the
|
||||
* same antenna selected each time.
|
||||
*/
|
||||
void operacake_sctimer_reset_state() {
|
||||
SCT_CTRL |= SCT_CTRL_HALT_L(1);
|
||||
|
||||
// Clear the counter value
|
||||
SCT_CTRL |= SCT_CTRL_CLRCTR_L(1);
|
||||
|
||||
// Reset to select the first port
|
||||
SCT_OUTPUT = default_output;
|
||||
|
||||
SCT_CTRL &= ~SCT_CTRL_HALT_L(1);
|
||||
}
|
41
firmware/common/operacake_sctimer.h
Normal file
41
firmware/common/operacake_sctimer.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2016 Dominic Spill <dominicgs@gmail.com>
|
||||
* Copyright 2018 Schuyler St. Leger
|
||||
* Copyright 2021 Great Scott Gadgets
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __OPERACAKE_SCTIMER_H
|
||||
#define __OPERACAKE_SCTIMER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct operacake_dwell_times {
|
||||
uint32_t dwell;
|
||||
uint8_t port;
|
||||
};
|
||||
|
||||
void operacake_sctimer_init();
|
||||
void operacake_sctimer_enable(bool enable);
|
||||
void operacake_sctimer_set_dwell_times(struct operacake_dwell_times *times, int n);
|
||||
void operacake_sctimer_stop();
|
||||
void operacake_sctimer_reset_state();
|
||||
|
||||
#endif /* __OPERACAKE_SCTIMER_H */
|
1764
firmware/common/sct.h
Normal file
1764
firmware/common/sct.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||
* Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
|
||||
* Copyright 2017 Schuyler St. Leger <schuyler.st.leger@gmail.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
@ -159,7 +160,9 @@ void sgpio_configure(
|
||||
const uint_fast8_t slice_count = config->slice_mode_multislice ? 8 : 1;
|
||||
const uint_fast8_t clk_capture_mode = (direction == SGPIO_DIRECTION_TX) ? 0 : 0;
|
||||
|
||||
uint32_t slice_enable_mask = 0;
|
||||
// Also enable slice D for clkout to the SCTimer
|
||||
uint32_t slice_enable_mask = BIT3;
|
||||
|
||||
/* Configure Slice A, I, E, J, C, K, F, L (sgpio_slice_mode_multislice mode) */
|
||||
for(uint_fast8_t i=0; i<slice_count; i++)
|
||||
{
|
||||
|
@ -61,6 +61,7 @@ set(SRC_M4
|
||||
"${PATH_HACKRF_FIRMWARE_COMMON}/crc.c"
|
||||
"${PATH_HACKRF_FIRMWARE_COMMON}/rom_iap.c"
|
||||
"${PATH_HACKRF_FIRMWARE_COMMON}/operacake.c"
|
||||
"${PATH_HACKRF_FIRMWARE_COMMON}/operacake_sctimer.c"
|
||||
)
|
||||
|
||||
set(SRC_M0 sgpio_m0.s)
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "usb_api_transceiver.h"
|
||||
|
||||
#include "hackrf_ui.h"
|
||||
#include "operacake_sctimer.h"
|
||||
|
||||
#include <libopencm3/cm3/vector.h>
|
||||
#include "usb_bulk_buffer.h"
|
||||
|
||||
@ -247,6 +249,7 @@ transceiver_mode_t transceiver_mode(void) {
|
||||
|
||||
void set_transceiver_mode(const transceiver_mode_t new_transceiver_mode) {
|
||||
baseband_streaming_disable(&sgpio_config);
|
||||
operacake_sctimer_reset_state();
|
||||
|
||||
usb_endpoint_flush(&usb_endpoint_bulk_in);
|
||||
usb_endpoint_flush(&usb_endpoint_bulk_out);
|
||||
|
Reference in New Issue
Block a user