1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
|
/*
* Copyright 2017-2022 Great Scott Gadgets <info@greatscottgadgets.com>
* Copyright 2018 Schuyler St. Leger
*
* 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.
*
* On Praline, instead, MS0/CLK1 (SCT_CLK) 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);
#ifndef PRALINE
// 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
uint8_t sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_1;
#else
// Configure pin P6_4 as SCT_IN_6
scu_pinmux(P6_4, SCU_CLK_IN | SCU_CONF_FUNCTION1);
// Use the GIMA to connect MS0/CLK1 (SCT_CLK) on pin P6_4 to the SCTimer
GIMA_CTIN_6_IN = 0x0 << 4;
uint8_t sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_6;
#endif
// 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_clock_input;
// 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);
}
|