mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-24 16:17:50 +00:00
Upstream merge to make new revision of PortaPack work (#206)
* Power: Turn off additional peripheral clock branches. * Update schematic with new symbol table and KiCad standard symbols. Fix up wires. * Schematic: Update power net labels. * Schematic: Update footprint names to match library changes. * Schematic: Update header vendor and part numbers. * Schematic: Specify (arbitrary) value for PDN# net. * Schematic: Remove fourth fiducial. Not standard practice, and was taking up valuable board space. * Schematic: Add reference oscillator -- options for clipped sine or HCMOS output. * Schematic: Update copyright year. * Schematic: Remove CLKOUT to CPLD. It was a half-baked idea. * Schematic: Add (experimental) GPS circuit. Add note about charging circuit. Update date and revision to match PCB. * PCB: Update from schematic change: now revision 20180819. Diff was extensive due to net renumbering... * PCB: Fix GPS courtyard to accommodate crazy solder paste recommendation in integration manual. PCB: Address DRC clearance violation between via and oscillator pad. * PCB: Update copyright on drawing. * Update schematic and PCB date and revision. * gitignore: Sublime Text editor project/workspace files * Power: Power up or power down peripheral clock at appropriate times, so firmware doesn't freeze... * Clocking: Fix incorrect shift for CGU IDIVx_CTRL.PD field. * LPC43xx: Add CGU IDIVx struct/union type. * Power: Switch off unused IDIV dividers. Make note of active IDIVs and their use. * HackRF Mode: Upgrade firmware to 2018.01.1 (API 1.02) * MAX V CPLD: Refactor class to look more like Xilinx CoolRunner II CPLD class. * MAX V CPLD: Add BYPASS, SAMPLE support. Rename enter_isp -> enable, exit_isp -> disable. Use SAMPLE at start of flash process, which somehow addresses the problem where CFM wouldn't load into SRAM (and become the active bitstream) after flashing. * MAX V CPLD: Reverse verify data checking logic to make it a little faster. * CPLD: After reprogramming flash, immediately clamp I/O signals, load to SRAM, and "execute" the new bitstream. * Si5351: Refactor code, make one of the registers more type-safe. Clock Manager: Track selected reference clock source for later use in user interface. * Clock Manager: Add note about PPM only affecting Si5351C PLLA, which always runs from the HackRF 25MHz crystal. It is assumed an external clock does not need adjustment, though I am open to being convinced otherwise... * PPM UI: Show "EXT" when showing PPM adjustment and reference clock is external. * CPLD: Add pins and logic for new PortaPack hardware feature(s). * CPLD: Bitstream to support new hardware features. * Clock Generator: Add a couple more setter methods for ClockControl registers. * Clock Manager: Use shared MCU CLKIN clock control configuration constant. * Clock Manager: Reduce MCU CLKIN driver current. 2mA should be plenty. * Clock Manager: Remove redundant clock generator output enable. * Bootstrap: Remove unnecessary ldscript hack to locate SPIFI mode change code in RAM. * Bootstrap: Get CPU operating at max frequency as soon as possible. Update SPIFI speed comment. Make some more LPC43xx types into unions with uint32_t. * Bootstrap: Explicitly configure IDIVB for SPIFI, despite LPC43xx bootloader setting it. * Clock Manager: Init peripherals before CPLD reconfig. Do the clock generator setup after, so we can check presence of PortaPack reference clock with the help of the latest CPLD bitstream. * Clock Manager: Reverse sense of conditional that determines crystal or non-crystal reference source. This is for an expected upcoming change where multiple external options can be differentiated. * Bootstrap: Consolidate clock configuration, update SPIFI rate comment. * Clock Manager: Use IDIVA for clock source for all peripherals, instead of PLL1. Should make switching easier going forward. Don't use IRC as clock during initial clock manager configuration. Until we switch to GP_CLKIN, we should go flat out... * ChibiOS M0: Change default clock speed to 204MHz, since bootstrap now maxes out clock speed before starting M0 execution. * PortaPack IO: Expose method to set reference oscillator enable pin. * Pin configuration: Do SPIFI pin config with other pins, in preparation for eliminating separate bootloader. * Pin configuration: Disable input buffers on pins that are never read. * Revert "ChibiOS M0: Change default clock speed to 204MHz, since bootstrap now maxes out clock speed before starting M0 execution." This reverts commit c0e2bb6cc4cc656769323bdbb8ee5a16d2d5bb03. * Remove unused board files. * Add LPC43xx functions. * chibios: Replace code with per-peripheral structs defining clocks, interrupts, and reset bits. * LPC43xx: Add MCPWM peripheral struct. * clock generator: Use recommended PLL reset register value. Datasheet recommends a value. AN619 is quiet on the topic, claims the low nibble is default 0b0000. * GPIO: Tweak masking of SCU function. I don't remember why I thought this was necessary... * HAL: Explicitly turn on timer peripheral clocks used as systicks, during init. * SCU: Add struct to hold pin configuration. * PAL: Add functions to address The Glitch. https://greatscottgadgets.com/2018/02-28-we-fixed-the-glitch/ * PAL/board: New IO initialization code Declare initial state for SCU pin config, GPIOs. Apply initial state during PAL init. Perform VAA slow turn-on to address The Glitch. * Merge M0 and M4 to eliminate need for bootstrap firmware During _early_init, detect if we're running on the M4 or M0. If M4: do M4-specific core initialization, reset peripherals, speed up SPIFI clock, start M0, go to sleep. If M0: do all the other things. * Pins: Miscellaneous SCU configuration tweaks. * Little code clarity improvement. * bootstrap: Remove, not necessary. * Clock Manager: Large re-working to support external references. * Fix merge conflicts
This commit is contained in:
@@ -42,14 +42,13 @@ set(FIRMWARE_FILENAME ${FIRMWARE_NAME}.bin)
|
||||
|
||||
add_subdirectory(application)
|
||||
add_subdirectory(baseband)
|
||||
add_subdirectory(bootstrap)
|
||||
|
||||
# NOTE: Dependencies break if the .bin files aren't included in DEPENDS. WTF, CMake?
|
||||
add_custom_command(
|
||||
OUTPUT ${FIRMWARE_FILENAME}
|
||||
COMMAND ${MAKE_SPI_IMAGE} ${bootstrap_BINARY_DIR}/bootstrap.bin ${baseband_BINARY_DIR}/baseband.img ${application_BINARY_DIR}/application.bin ${FIRMWARE_FILENAME}
|
||||
DEPENDS bootstrap baseband application ${MAKE_SPI_IMAGE}
|
||||
${bootstrap_BINARY_DIR}/bootstrap.bin ${baseband_BINARY_DIR}/baseband.img ${application_BINARY_DIR}/application.bin
|
||||
COMMAND ${MAKE_SPI_IMAGE} ${application_BINARY_DIR}/application.bin ${baseband_BINARY_DIR}/baseband.img ${FIRMWARE_FILENAME}
|
||||
DEPENDS baseband application ${MAKE_SPI_IMAGE}
|
||||
${baseband_BINARY_DIR}/baseband.img ${application_BINARY_DIR}/application.bin
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
|
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "clock_manager.hpp"
|
||||
|
||||
#include "portapack_io.hpp"
|
||||
|
||||
#include "hackrf_hal.hpp"
|
||||
using namespace hackrf::one;
|
||||
|
||||
@@ -41,6 +43,7 @@ static constexpr uint32_t systick_load(const uint32_t clock_source_f) {
|
||||
}
|
||||
|
||||
constexpr uint32_t clock_source_irc_f = 12000000;
|
||||
constexpr uint32_t clock_source_pll1_boot_f = 96000000;
|
||||
//constexpr uint32_t clock_source_gp_clkin = 20000000;
|
||||
constexpr uint32_t clock_source_pll1_step_f = 100000000;
|
||||
constexpr uint32_t clock_source_pll1_f = 200000000;
|
||||
@@ -54,8 +57,8 @@ constexpr uint32_t si5351_vco_f = 800000000;
|
||||
constexpr uint32_t i2c0_bus_f = 400000;
|
||||
constexpr uint32_t i2c0_high_period_ns = 900;
|
||||
|
||||
constexpr I2CClockConfig i2c_clock_config_400k_slow_clock {
|
||||
.clock_source_f = clock_source_irc_f,
|
||||
constexpr I2CClockConfig i2c_clock_config_400k_boot_clock {
|
||||
.clock_source_f = clock_source_pll1_boot_f,
|
||||
.bus_f = i2c0_bus_f,
|
||||
.high_period_ns = i2c0_high_period_ns,
|
||||
};
|
||||
@@ -66,9 +69,9 @@ constexpr I2CClockConfig i2c_clock_config_400k_fast_clock {
|
||||
.high_period_ns = i2c0_high_period_ns,
|
||||
};
|
||||
|
||||
constexpr I2CConfig i2c_config_slow_clock {
|
||||
.high_count = i2c_clock_config_400k_slow_clock.i2c_high_count(),
|
||||
.low_count = i2c_clock_config_400k_slow_clock.i2c_low_count(),
|
||||
constexpr I2CConfig i2c_config_boot_clock {
|
||||
.high_count = i2c_clock_config_400k_boot_clock.i2c_high_count(),
|
||||
.low_count = i2c_clock_config_400k_boot_clock.i2c_low_count(),
|
||||
};
|
||||
|
||||
constexpr I2CConfig i2c_config_fast_clock {
|
||||
@@ -214,79 +217,104 @@ static_assert(si5351_ms_int_mcu_clkin.f_out() == mcu_clkin_f, "MS int MCU CLKIN
|
||||
|
||||
using namespace si5351;
|
||||
|
||||
constexpr ClockControl::Type si5351_clock_control_ms_src_xtal = ClockControl::MS_SRC_PLLA;
|
||||
constexpr ClockControl::Type si5351_clock_control_ms_src_clkin = ClockControl::MS_SRC_PLLB;
|
||||
static constexpr ClockControl::MultiSynthSource get_reference_clock_generator_pll(const ClockManager::ReferenceSource reference_source) {
|
||||
return (reference_source == ClockManager::ReferenceSource::Xtal)
|
||||
? ClockControl::MultiSynthSource::PLLA
|
||||
: ClockControl::MultiSynthSource::PLLB
|
||||
;
|
||||
}
|
||||
|
||||
constexpr ClockControls si5351_clock_control_common {
|
||||
ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Fractional | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Group | ClockControl::CLK_INV_Invert | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Group | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_8mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_8mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_2mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Fractional | ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_IDRV_6mA | ClockControl::CLK_SRC_MS_Self | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_Off,
|
||||
};
|
||||
constexpr ClockControls si5351_clock_control_common { {
|
||||
{ ClockControl::ClockCurrentDrive::_6mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Fractional, ClockControl::ClockPowerDown::Power_Off },
|
||||
{ ClockControl::ClockCurrentDrive::_6mA, ClockControl::ClockSource::MS_Group, ClockControl::ClockInvert::Invert, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off },
|
||||
{ ClockControl::ClockCurrentDrive::_6mA, ClockControl::ClockSource::MS_Group, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off },
|
||||
{ ClockControl::ClockCurrentDrive::_8mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off },
|
||||
{ ClockControl::ClockCurrentDrive::_8mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off },
|
||||
{ ClockControl::ClockCurrentDrive::_6mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off },
|
||||
{ ClockControl::ClockCurrentDrive::_2mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Fractional, ClockControl::ClockPowerDown::Power_Off },
|
||||
{ ClockControl::ClockCurrentDrive::_2mA, ClockControl::ClockSource::MS_Self, ClockControl::ClockInvert::Normal, get_reference_clock_generator_pll(ClockManager::ReferenceSource::Xtal), ClockControl::MultiSynthMode::Integer, ClockControl::ClockPowerDown::Power_Off },
|
||||
} };
|
||||
|
||||
constexpr ClockControls si5351_clock_control_xtal {
|
||||
si5351_clock_control_common[0] | si5351_clock_control_ms_src_xtal,
|
||||
si5351_clock_control_common[1] | si5351_clock_control_ms_src_xtal,
|
||||
si5351_clock_control_common[2] | si5351_clock_control_ms_src_xtal,
|
||||
si5351_clock_control_common[3] | si5351_clock_control_ms_src_xtal,
|
||||
si5351_clock_control_common[4] | si5351_clock_control_ms_src_xtal,
|
||||
si5351_clock_control_common[5] | si5351_clock_control_ms_src_xtal,
|
||||
si5351_clock_control_common[6] | si5351_clock_control_ms_src_xtal,
|
||||
si5351_clock_control_common[7] | si5351_clock_control_ms_src_xtal,
|
||||
};
|
||||
ClockManager::ReferenceSource ClockManager::get_reference_source() const {
|
||||
return reference_source;
|
||||
}
|
||||
|
||||
constexpr ClockControls si5351_clock_control_clkin {
|
||||
si5351_clock_control_common[0] | si5351_clock_control_ms_src_clkin,
|
||||
si5351_clock_control_common[1] | si5351_clock_control_ms_src_clkin,
|
||||
si5351_clock_control_common[2] | si5351_clock_control_ms_src_clkin,
|
||||
si5351_clock_control_common[3] | si5351_clock_control_ms_src_clkin,
|
||||
si5351_clock_control_common[4] | si5351_clock_control_ms_src_clkin,
|
||||
si5351_clock_control_common[5] | si5351_clock_control_ms_src_clkin,
|
||||
si5351_clock_control_common[6] | si5351_clock_control_ms_src_clkin,
|
||||
si5351_clock_control_common[7] | si5351_clock_control_ms_src_clkin,
|
||||
};
|
||||
static void portapack_tcxo_enable() {
|
||||
portapack::io.reference_oscillator(true);
|
||||
|
||||
void ClockManager::init() {
|
||||
/* Delay >10ms at 96MHz clock speed for reference oscillator to start. */
|
||||
/* Delay an additional 1ms (arbitrary) for the clock generator to detect a signal. */
|
||||
volatile uint32_t delay = 240000 + 24000;
|
||||
while(delay--);
|
||||
}
|
||||
|
||||
static void portapack_tcxo_disable() {
|
||||
portapack::io.reference_oscillator(false);
|
||||
}
|
||||
|
||||
#include "hackrf_gpio.hpp"
|
||||
using namespace hackrf::one;
|
||||
|
||||
void ClockManager::init_peripherals() {
|
||||
/* Must be sure to run the M4 core from IRC when messing with the signal
|
||||
* generator that sources the GP_CLKIN signal that drives the micro-
|
||||
* controller's PLL1 input.
|
||||
*/
|
||||
/* When booting from SPIFI, PLL1 is already running at 96MHz. */
|
||||
//run_from_irc();
|
||||
/* When booting from SPIFI, PLL1 is already running at 288MHz. */
|
||||
/* TODO: Refactor this blob, there's too much knowledge about post-boot
|
||||
* state, which can change depending on where we're running from -- SPIFI
|
||||
* or RAM or ???
|
||||
*/
|
||||
update_peripheral_clocks(cgu::CLK_SEL::IRC);
|
||||
start_peripherals(cgu::CLK_SEL::IRC);
|
||||
// PLL1 is running at 288 MHz upon bootstrap exit.
|
||||
LPC_CGU->IDIVA_CTRL.word =
|
||||
( 0 << 0) /* PD */
|
||||
| ( 2 << 2) /* IDIV (/3) */
|
||||
| ( 1 << 11) /* AUTOBLOCK */
|
||||
| ( 9 << 24) /* PLL1 */
|
||||
;
|
||||
|
||||
const auto clk_sel = cgu::CLK_SEL::IDIVA;
|
||||
set_clock(LPC_CGU->BASE_M4_CLK, clk_sel);
|
||||
set_clock(LPC_CGU->BASE_PERIPH_CLK, clk_sel);
|
||||
set_clock(LPC_CGU->BASE_APB1_CLK, clk_sel);
|
||||
set_clock(LPC_CGU->BASE_APB3_CLK, clk_sel);
|
||||
set_clock(LPC_CGU->BASE_SDIO_CLK, clk_sel);
|
||||
set_clock(LPC_CGU->BASE_SSP1_CLK, clk_sel);
|
||||
|
||||
// IDIVC should no longer be in use.
|
||||
LPC_CGU->IDIVC_CTRL.PD = 1;
|
||||
|
||||
i2c0.start(i2c_config_boot_clock);
|
||||
}
|
||||
|
||||
void ClockManager::init_clock_generator() {
|
||||
clock_generator.reset();
|
||||
clock_generator.set_crystal_internal_load_capacitance(CrystalInternalLoadCapacitance::XTAL_CL_8pF);
|
||||
clock_generator.enable_fanout();
|
||||
clock_generator.set_pll_input_sources(si5351_pll_input_sources);
|
||||
|
||||
const auto clkin_present = !clock_generator.clkin_loss_of_signal();
|
||||
auto clkin_valid = false;
|
||||
|
||||
if( clkin_present ) {
|
||||
// Measure Si5351B CLKIN frequency against LPC43xx IRC oscillator
|
||||
set_gp_clkin_to_clkin_direct();
|
||||
start_frequency_monitor_measurement(cgu::CLK_SEL::GP_CLKIN);
|
||||
wait_For_frequency_monitor_measurement_done();
|
||||
const auto clkin_frequency = get_frequency_monitor_measurement_in_hertz();
|
||||
|
||||
// CLKIN is required to be 10MHz. FREQ_MON measurement is accurate to 1.5%
|
||||
// due to LPC43xx IRC oscillator precision.
|
||||
clkin_valid = (clkin_frequency >= 9850000) && (clkin_frequency <= 10150000);
|
||||
}
|
||||
|
||||
clock_generator.set_clock_control(
|
||||
clkin_valid ? si5351_clock_control_clkin : si5351_clock_control_xtal
|
||||
clock_generator_output_mcu_clkin,
|
||||
si5351_clock_control_common[clock_generator_output_mcu_clkin].clk_src(ClockControl::ClockSource::CLKIN).clk_pdn(ClockControl::ClockPowerDown::Power_On)
|
||||
);
|
||||
clock_generator.enable_output(clock_generator_output_mcu_clkin);
|
||||
|
||||
const auto reference_source = choose_reference_source();
|
||||
|
||||
clock_generator.disable_output(clock_generator_output_mcu_clkin);
|
||||
|
||||
const auto ref_pll = get_reference_clock_generator_pll(reference_source);
|
||||
const ClockControls si5351_clock_control = ClockControls { {
|
||||
si5351_clock_control_common[0].ms_src(ref_pll),
|
||||
si5351_clock_control_common[1].ms_src(ref_pll),
|
||||
si5351_clock_control_common[2].ms_src(ref_pll),
|
||||
si5351_clock_control_common[3].ms_src(ref_pll),
|
||||
si5351_clock_control_common[4].ms_src(ref_pll),
|
||||
si5351_clock_control_common[5].ms_src(ref_pll),
|
||||
si5351_clock_control_common[6].ms_src(ref_pll),
|
||||
si5351_clock_control_common[7].ms_src(ref_pll),
|
||||
} };
|
||||
clock_generator.set_clock_control(si5351_clock_control);
|
||||
|
||||
clock_generator.write(si5351_pll_a_xtal_reg);
|
||||
clock_generator.write(si5351_pll_b_clkin_reg);
|
||||
@@ -297,22 +325,65 @@ void ClockManager::init() {
|
||||
clock_generator.write(si5351_ms_4_reg);
|
||||
clock_generator.write(si5351_ms_5_reg);
|
||||
clock_generator.write(si5351_ms6_7_off_mcu_clkin_reg);
|
||||
|
||||
clock_generator.reset_plls();
|
||||
|
||||
// Wait for both PLLs to lock.
|
||||
// TODO: Disable the unused PLL?
|
||||
while((clock_generator.device_status() & 0x60) != 0);
|
||||
|
||||
clock_generator.set_clock_control(
|
||||
clock_generator_output_mcu_clkin,
|
||||
si5351_clock_control_common[clock_generator_output_mcu_clkin].ms_src(ref_pll).clk_pdn(ClockControl::ClockPowerDown::Power_On)
|
||||
);
|
||||
clock_generator.enable_output(clock_generator_output_mcu_clkin);
|
||||
|
||||
set_m4_clock_to_pll1();
|
||||
}
|
||||
|
||||
uint32_t ClockManager::measure_gp_clkin_frequency() {
|
||||
// Measure Si5351B CLKIN frequency against LPC43xx IRC oscillator
|
||||
start_frequency_monitor_measurement(cgu::CLK_SEL::GP_CLKIN);
|
||||
wait_For_frequency_monitor_measurement_done();
|
||||
return get_frequency_monitor_measurement_in_hertz();
|
||||
}
|
||||
|
||||
ClockManager::ReferenceSource ClockManager::detect_reference_source() {
|
||||
if( clock_generator.clkin_loss_of_signal() ) {
|
||||
// No external reference. Turn on PortaPack reference (if present).
|
||||
portapack_tcxo_enable();
|
||||
|
||||
if( clock_generator.clkin_loss_of_signal() ) {
|
||||
// No PortaPack reference was detected. Choose the HackRF crystal as the reference.
|
||||
return ReferenceSource::Xtal;
|
||||
} else {
|
||||
return ReferenceSource::PortaPack;
|
||||
}
|
||||
} else {
|
||||
return ReferenceSource::External;
|
||||
}
|
||||
}
|
||||
|
||||
ClockManager::ReferenceSource ClockManager::choose_reference_source() {
|
||||
const auto detected_reference = detect_reference_source();
|
||||
|
||||
if( (detected_reference == ReferenceSource::External) ||
|
||||
(detected_reference == ReferenceSource::PortaPack) ) {
|
||||
const auto frequency = measure_gp_clkin_frequency();
|
||||
if( (frequency >= 9850000) && (frequency <= 10150000) ) {
|
||||
return detected_reference;
|
||||
}
|
||||
}
|
||||
|
||||
portapack_tcxo_disable();
|
||||
return ReferenceSource::Xtal;
|
||||
}
|
||||
|
||||
void ClockManager::shutdown() {
|
||||
run_from_irc();
|
||||
// run_from_irc();
|
||||
clock_generator.reset();
|
||||
}
|
||||
|
||||
void ClockManager::run_from_irc() {
|
||||
change_clock_configuration(cgu::CLK_SEL::IRC);
|
||||
}
|
||||
|
||||
void ClockManager::run_at_full_speed() {
|
||||
change_clock_configuration(cgu::CLK_SEL::PLL1);
|
||||
}
|
||||
|
||||
void ClockManager::enable_codec_clocks() {
|
||||
clock_generator.enable_clock(clock_generator_output_codec);
|
||||
clock_generator.enable_clock(clock_generator_output_cpld);
|
||||
@@ -373,6 +444,10 @@ void ClockManager::set_sampling_frequency(const uint32_t frequency) {
|
||||
}
|
||||
|
||||
void ClockManager::set_reference_ppb(const int32_t ppb) {
|
||||
/* NOTE: This adjustment only affects PLLA, which is derived from the 25MHz crystal.
|
||||
* It is assumed an external clock coming in to PLLB is sufficiently accurate as to not need adjustment.
|
||||
* TODO: Revisit the above policy. It may be good to allow adjustment of the external reference too.
|
||||
*/
|
||||
constexpr uint32_t pll_multiplier = si5351_pll_xtal_25m.a;
|
||||
constexpr uint32_t denominator = 1000000 / pll_multiplier;
|
||||
const uint32_t new_a = (ppb >= 0) ? pll_multiplier : (pll_multiplier - 1);
|
||||
@@ -389,59 +464,6 @@ void ClockManager::set_reference_ppb(const int32_t ppb) {
|
||||
clock_generator.write(pll_a_reg);
|
||||
}
|
||||
|
||||
void ClockManager::change_clock_configuration(const cgu::CLK_SEL clk_sel) {
|
||||
/* If starting PLL1, turn on the clock feeding GP_CLKIN */
|
||||
if( clk_sel == cgu::CLK_SEL::PLL1 ) {
|
||||
enable_gp_clkin_source();
|
||||
}
|
||||
|
||||
if( clk_sel == cgu::CLK_SEL::XTAL ) {
|
||||
enable_xtal_oscillator();
|
||||
}
|
||||
|
||||
stop_peripherals();
|
||||
|
||||
set_m4_clock_to_irc();
|
||||
|
||||
update_peripheral_clocks(clk_sel);
|
||||
|
||||
if( clk_sel == cgu::CLK_SEL::PLL1 ) {
|
||||
set_m4_clock_to_pll1();
|
||||
} else {
|
||||
power_down_pll1();
|
||||
}
|
||||
|
||||
start_peripherals(clk_sel);
|
||||
|
||||
if( clk_sel != cgu::CLK_SEL::XTAL ) {
|
||||
disable_xtal_oscillator();
|
||||
}
|
||||
|
||||
/* If not using PLL1, disable clock feeding GP_CLKIN */
|
||||
if( clk_sel != cgu::CLK_SEL::PLL1 ) {
|
||||
stop_audio_pll();
|
||||
disable_gp_clkin_source();
|
||||
}
|
||||
}
|
||||
|
||||
void ClockManager::enable_gp_clkin_source() {
|
||||
clock_generator.enable_clock(clock_generator_output_mcu_clkin);
|
||||
clock_generator.enable_output(clock_generator_output_mcu_clkin);
|
||||
}
|
||||
|
||||
void ClockManager::disable_gp_clkin_source() {
|
||||
clock_generator.disable_clock(clock_generator_output_mcu_clkin);
|
||||
clock_generator.disable_output(clock_generator_output_mcu_clkin);
|
||||
}
|
||||
|
||||
void ClockManager::set_gp_clkin_to_clkin_direct() {
|
||||
clock_generator.set_clock_control(
|
||||
clock_generator_output_mcu_clkin,
|
||||
{ ClockControl::CLK_IDRV_2mA | ClockControl::CLK_SRC_CLKIN | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_On }
|
||||
);
|
||||
enable_gp_clkin_source();
|
||||
}
|
||||
|
||||
void ClockManager::start_frequency_monitor_measurement(const cgu::CLK_SEL clk_sel) {
|
||||
// Measure a clock input for 480 cycles of the LPC43xx IRC.
|
||||
LPC_CGU->FREQ_MON = LPC_CGU_FREQ_MON_Type {
|
||||
@@ -475,48 +497,94 @@ void ClockManager::disable_xtal_oscillator() {
|
||||
LPC_CGU->XTAL_OSC_CTRL.ENABLE = 0;
|
||||
}
|
||||
|
||||
void ClockManager::set_m4_clock_to_irc() {
|
||||
/* Set M4 clock to safe default speed (~12MHz IRC) */
|
||||
set_clock(LPC_CGU->BASE_M4_CLK, cgu::CLK_SEL::IRC);
|
||||
systick_adjust_period(systick_count_irc);
|
||||
//_clock_f = clock_source_irc_f;
|
||||
halLPCSetSystemClock(clock_source_irc_f);
|
||||
}
|
||||
|
||||
void ClockManager::set_m4_clock_to_pll1() {
|
||||
/* Incantation from LPC43xx UM10503 section 12.2.1.1, to bring the M4
|
||||
* core clock speed to the 110 - 204MHz range.
|
||||
*/
|
||||
|
||||
/* Set M4 clock to safe default speed (~12MHz IRC) */
|
||||
|
||||
i2c0.stop();
|
||||
|
||||
// All other peripherals capable of running at 204 MHz.
|
||||
LPC_CGU->IDIVA_CTRL.word =
|
||||
( 0 << 0) /* PD */
|
||||
| ( 0 << 2) /* IDIV (/1) */
|
||||
| ( 1 << 11) /* AUTOBLOCK */
|
||||
| ( 1 << 24) /* IRC */
|
||||
;
|
||||
|
||||
systick_adjust_period(systick_count_irc);
|
||||
halLPCSetSystemClock(clock_source_irc_f);
|
||||
|
||||
// SPIFI clock
|
||||
LPC_CGU->IDIVB_CTRL.word =
|
||||
( 0 << 0) /* PD */
|
||||
| ( 0 << 2) /* IDIV (/1) */
|
||||
| ( 1 << 11) /* AUTOBLOCK */
|
||||
| ( 1 << 24) /* IRC */
|
||||
;
|
||||
|
||||
/* Step into the 90-110MHz M4 clock range */
|
||||
/* Fclkin = 40M
|
||||
* /N=2 = 20M = PFDin
|
||||
* Fcco = PFDin * (M=10) = 200M
|
||||
* Fclk = Fcco / (2*(P=1)) = 100M
|
||||
*/
|
||||
cgu::pll1::ctrl({
|
||||
.pd = 0,
|
||||
.pd = 1,
|
||||
.bypass = 0,
|
||||
.fbsel = 0,
|
||||
.direct = 0,
|
||||
.psel = 0,
|
||||
.autoblock = 1,
|
||||
.nsel = 0,
|
||||
.msel = 4,
|
||||
.nsel = 1,
|
||||
.msel = 9,
|
||||
.clk_sel = cgu::CLK_SEL::GP_CLKIN,
|
||||
});
|
||||
|
||||
cgu::pll1::enable();
|
||||
while( !cgu::pll1::is_locked() );
|
||||
|
||||
/* Switch M4 clock to PLL1 running at intermediate rate */
|
||||
set_clock(LPC_CGU->BASE_M4_CLK, cgu::CLK_SEL::PLL1);
|
||||
// All other peripherals capable of running at 204 MHz.
|
||||
LPC_CGU->IDIVA_CTRL.word =
|
||||
( 0 << 0) /* PD */
|
||||
| ( 0 << 2) /* IDIV (/1) */
|
||||
| ( 1 << 11) /* AUTOBLOCK */
|
||||
| ( 9 << 24) /* PLL1 */
|
||||
;
|
||||
|
||||
systick_adjust_period(systick_count_pll1_step);
|
||||
//_clock_f = clock_source_pll1_step_f;
|
||||
halLPCSetSystemClock(clock_source_pll1_step_f);
|
||||
|
||||
// SPIFI clock
|
||||
LPC_CGU->IDIVB_CTRL.word =
|
||||
( 0 << 0) /* PD */
|
||||
| ( 0 << 2) /* IDIV (/1) */
|
||||
| ( 1 << 11) /* AUTO BLOCK */
|
||||
| ( 9 << 24) /* PLL1 */
|
||||
;
|
||||
|
||||
/* Delay >50us at 90-110MHz clock speed */
|
||||
volatile uint32_t delay = 1400;
|
||||
while(delay--);
|
||||
|
||||
// SPIFI clock
|
||||
LPC_CGU->IDIVB_CTRL.word =
|
||||
( 0 << 0) /* PD */
|
||||
| ( 1 << 2) /* IDIV (/2) */
|
||||
| ( 1 << 11) /* AUTOBLOCK */
|
||||
| ( 9 << 24) /* PLL1 */
|
||||
;
|
||||
|
||||
/* Remove /2P divider from PLL1 output to achieve full speed */
|
||||
cgu::pll1::direct();
|
||||
|
||||
systick_adjust_period(systick_count_pll1);
|
||||
//_clock_f = clock_source_pll1_f;
|
||||
halLPCSetSystemClock(clock_source_pll1_f);
|
||||
|
||||
i2c0.start(i2c_config_fast_clock);
|
||||
}
|
||||
|
||||
void ClockManager::power_down_pll1() {
|
||||
@@ -565,8 +633,8 @@ void ClockManager::start_audio_pll() {
|
||||
}
|
||||
|
||||
void ClockManager::set_base_audio_clock_divider(const size_t divisor) {
|
||||
LPC_CGU->IDIVC_CTRL =
|
||||
(0 << 1)
|
||||
LPC_CGU->IDIVC_CTRL.word =
|
||||
(0 << 0)
|
||||
| ((divisor - 1) << 2)
|
||||
| (1 << 11)
|
||||
| (toUType(cgu::CLK_SEL::PLL0AUDIO) << 24)
|
||||
@@ -582,28 +650,3 @@ void ClockManager::stop_audio_pll() {
|
||||
void ClockManager::stop_peripherals() {
|
||||
i2c0.stop();
|
||||
}
|
||||
|
||||
void ClockManager::update_peripheral_clocks(const cgu::CLK_SEL clk_sel) {
|
||||
/* TODO: Extract a structure to represent clock settings for different
|
||||
* modes.
|
||||
*/
|
||||
set_clock(LPC_CGU->BASE_PERIPH_CLK, clk_sel);
|
||||
LPC_CGU->IDIVB_CTRL =
|
||||
(0 << 1)
|
||||
| (1 << 2)
|
||||
| (1 << 11)
|
||||
| (toUType(clk_sel) << 24)
|
||||
;
|
||||
set_clock(LPC_CGU->BASE_APB1_CLK, clk_sel);
|
||||
set_clock(LPC_CGU->BASE_APB3_CLK, clk_sel);
|
||||
set_clock(LPC_CGU->BASE_SDIO_CLK, clk_sel);
|
||||
set_clock(LPC_CGU->BASE_SSP1_CLK, clk_sel);
|
||||
}
|
||||
|
||||
void ClockManager::start_peripherals(const cgu::CLK_SEL clk_sel) {
|
||||
/* Start APB1 peripherals considering new clock */
|
||||
i2c0.start((clk_sel == cgu::CLK_SEL::PLL1)
|
||||
? i2c_config_fast_clock
|
||||
: i2c_config_slow_clock
|
||||
);
|
||||
}
|
||||
|
@@ -33,21 +33,26 @@ using namespace lpc43xx;
|
||||
|
||||
class ClockManager {
|
||||
public:
|
||||
enum ReferenceSource {
|
||||
Xtal, /* 10 MHz crystal onboard the HackRF */
|
||||
PortaPack, /* 10 MHz TCXO on 20180820 and newer PortaPack revisions. */
|
||||
External, /* HackRF external clock input SMA, or from PortaPack with TCXO feature. */
|
||||
};
|
||||
|
||||
constexpr ClockManager(
|
||||
I2C& i2c0,
|
||||
si5351::Si5351& clock_generator
|
||||
) : i2c0(i2c0),
|
||||
clock_generator(clock_generator)/*,
|
||||
clock_generator(clock_generator),
|
||||
reference_source(ReferenceSource::Xtal)/*
|
||||
_clock_f(0)*/
|
||||
{
|
||||
}
|
||||
|
||||
void init();
|
||||
void init_peripherals();
|
||||
void init_clock_generator();
|
||||
void shutdown();
|
||||
|
||||
void run_from_irc();
|
||||
void run_at_full_speed();
|
||||
|
||||
void start_audio_pll();
|
||||
void stop_audio_pll();
|
||||
|
||||
@@ -68,15 +73,14 @@ public:
|
||||
|
||||
uint32_t get_frequency_monitor_measurement_in_hertz();
|
||||
|
||||
ReferenceSource get_reference_source() const;
|
||||
|
||||
private:
|
||||
I2C& i2c0;
|
||||
si5351::Si5351& clock_generator;
|
||||
ReferenceSource reference_source;
|
||||
//uint32_t _clock_f;
|
||||
|
||||
void change_clock_configuration(const cgu::CLK_SEL clk_sel);
|
||||
|
||||
void enable_gp_clkin_source();
|
||||
void disable_gp_clkin_source();
|
||||
void set_gp_clkin_to_clkin_direct();
|
||||
|
||||
void start_frequency_monitor_measurement(const cgu::CLK_SEL clk_sel);
|
||||
@@ -91,8 +95,11 @@ private:
|
||||
void power_down_pll1();
|
||||
|
||||
void stop_peripherals();
|
||||
void update_peripheral_clocks(const cgu::CLK_SEL clk_sel);
|
||||
void start_peripherals(const cgu::CLK_SEL clk_sel);
|
||||
|
||||
uint32_t measure_gp_clkin_frequency();
|
||||
|
||||
ClockManager::ReferenceSource detect_reference_source();
|
||||
ClockManager::ReferenceSource choose_reference_source();
|
||||
};
|
||||
|
||||
#endif/*__CLOCK_MANAGER_H__*/
|
||||
|
@@ -39,10 +39,10 @@ void Si5351::reset() {
|
||||
write_register(Register::PLLInputSource, 0x00);
|
||||
|
||||
_clock_control = {
|
||||
ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_PDN_Power_Off
|
||||
ClockControl::power_off(), ClockControl::power_off(),
|
||||
ClockControl::power_off(), ClockControl::power_off(),
|
||||
ClockControl::power_off(), ClockControl::power_off(),
|
||||
ClockControl::power_off(), ClockControl::power_off()
|
||||
};
|
||||
update_all_clock_control();
|
||||
|
||||
|
@@ -33,6 +33,8 @@
|
||||
|
||||
namespace si5351 {
|
||||
|
||||
using reg_t = uint8_t;
|
||||
|
||||
namespace Register {
|
||||
enum {
|
||||
DeviceStatus = 0,
|
||||
@@ -96,41 +98,101 @@ namespace DeviceStatus {
|
||||
};
|
||||
}
|
||||
|
||||
namespace ClockControl {
|
||||
using Type = uint8_t;
|
||||
|
||||
enum {
|
||||
CLK_IDRV_Mask = (0b11 << 0),
|
||||
CLK_IDRV_2mA = (0b00 << 0),
|
||||
CLK_IDRV_4mA = (0b01 << 0),
|
||||
CLK_IDRV_6mA = (0b10 << 0),
|
||||
CLK_IDRV_8mA = (0b11 << 0),
|
||||
|
||||
CLK_SRC_Mask = (0b11 << 2),
|
||||
CLK_SRC_XTAL = (0b00 << 2),
|
||||
CLK_SRC_CLKIN = (0b01 << 2),
|
||||
CLK_SRC_MS_Group = (0b10 << 2),
|
||||
CLK_SRC_MS_Self = (0b11 << 2),
|
||||
|
||||
CLK_INV_Mask = (1 << 4),
|
||||
CLK_INV_Normal = (0 << 4),
|
||||
CLK_INV_Invert = (1 << 4),
|
||||
|
||||
MS_SRC_Mask = (1 << 5),
|
||||
MS_SRC_PLLA = (0 << 5),
|
||||
MS_SRC_PLLB = (1 << 5),
|
||||
|
||||
MS_INT_Mask = (1 << 6),
|
||||
MS_INT_Fractional = (0 << 6),
|
||||
MS_INT_Integer = (1 << 6),
|
||||
|
||||
CLK_PDN_Mask = (1 << 7),
|
||||
CLK_PDN_Power_On = (0 << 7),
|
||||
CLK_PDN_Power_Off = (1 << 7),
|
||||
struct ClockControl {
|
||||
enum ClockCurrentDrive {
|
||||
_2mA = 0b00,
|
||||
_4mA = 0b01,
|
||||
_6mA = 0b10,
|
||||
_8mA = 0b11,
|
||||
};
|
||||
}
|
||||
|
||||
using ClockControls = std::array<ClockControl::Type, 8>;
|
||||
enum ClockSource {
|
||||
Xtal = 0b00,
|
||||
CLKIN = 0b01,
|
||||
MS_Group = 0b10,
|
||||
MS_Self = 0b11,
|
||||
};
|
||||
|
||||
enum ClockInvert {
|
||||
Normal = 0,
|
||||
Invert = 1,
|
||||
};
|
||||
|
||||
enum MultiSynthSource {
|
||||
PLLA = 0,
|
||||
PLLB = 1,
|
||||
};
|
||||
|
||||
enum MultiSynthMode {
|
||||
Fractional = 0,
|
||||
Integer = 1,
|
||||
};
|
||||
|
||||
enum ClockPowerDown {
|
||||
Power_On = 0,
|
||||
Power_Off = 1,
|
||||
};
|
||||
|
||||
reg_t CLK_IDRV : 2;
|
||||
reg_t CLK_SRC : 2;
|
||||
reg_t CLK_INV : 1;
|
||||
reg_t MS_SRC : 1;
|
||||
reg_t MS_INT : 1;
|
||||
reg_t CLK_PDN : 1;
|
||||
|
||||
constexpr ClockControl(
|
||||
ClockCurrentDrive clk_idrv,
|
||||
ClockSource clk_src,
|
||||
ClockInvert clk_inv,
|
||||
MultiSynthSource ms_src,
|
||||
MultiSynthMode ms_int,
|
||||
ClockPowerDown clk_pdn
|
||||
) : CLK_IDRV(clk_idrv),
|
||||
CLK_SRC(clk_src),
|
||||
CLK_INV(clk_inv),
|
||||
MS_SRC(ms_src),
|
||||
MS_INT(ms_int),
|
||||
CLK_PDN(clk_pdn)
|
||||
{
|
||||
}
|
||||
|
||||
ClockControl clk_src(const ClockSource value) const {
|
||||
auto result = *this;
|
||||
result.CLK_SRC = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
ClockControl ms_src(const MultiSynthSource value) const {
|
||||
auto result = *this;
|
||||
result.MS_SRC = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
ClockControl clk_pdn(const ClockPowerDown value) const {
|
||||
auto result = *this;
|
||||
result.CLK_PDN = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr operator reg_t() {
|
||||
return *reinterpret_cast<reg_t*>(this);
|
||||
}
|
||||
|
||||
static constexpr ClockControl power_off() {
|
||||
return {
|
||||
ClockCurrentDrive::_2mA,
|
||||
ClockSource::Xtal,
|
||||
ClockInvert::Normal,
|
||||
MultiSynthSource::PLLA,
|
||||
MultiSynthMode::Fractional,
|
||||
ClockPowerDown::Power_Off,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(ClockControl) == 1, "ClockControl size is not eight bits");
|
||||
|
||||
using ClockControls = std::array<ClockControl, 8>;
|
||||
|
||||
namespace CrystalInternalLoadCapacitance {
|
||||
using Type = uint8_t;
|
||||
@@ -289,10 +351,10 @@ public:
|
||||
|
||||
constexpr Si5351(I2C& bus, I2C::address_t address) :
|
||||
_clock_control({
|
||||
ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_PDN_Power_Off,
|
||||
ClockControl::CLK_PDN_Power_Off, ClockControl::CLK_PDN_Power_Off
|
||||
ClockControl::power_off(), ClockControl::power_off(),
|
||||
ClockControl::power_off(), ClockControl::power_off(),
|
||||
ClockControl::power_off(), ClockControl::power_off(),
|
||||
ClockControl::power_off(), ClockControl::power_off()
|
||||
}),
|
||||
_bus(bus),
|
||||
_address(address),
|
||||
@@ -302,6 +364,10 @@ public:
|
||||
|
||||
void reset();
|
||||
|
||||
uint8_t device_status() {
|
||||
return read_register(Register::DeviceStatus);
|
||||
}
|
||||
|
||||
void wait_for_device_ready() {
|
||||
while(device_status() & 0x80);
|
||||
}
|
||||
@@ -315,7 +381,8 @@ public:
|
||||
}
|
||||
|
||||
void reset_plls() {
|
||||
write_register(Register::PLLReset, 0xa0);
|
||||
// Datasheet recommends value 0xac, though the low nibble bits are not defined in AN619.
|
||||
write_register(Register::PLLReset, 0xac);
|
||||
}
|
||||
|
||||
regvalue_t read_register(const uint8_t reg);
|
||||
@@ -373,18 +440,18 @@ public:
|
||||
update_all_clock_control();
|
||||
}
|
||||
|
||||
void set_clock_control(const size_t n, const ClockControl::Type clock_control) {
|
||||
void set_clock_control(const size_t n, const ClockControl clock_control) {
|
||||
_clock_control[n] = clock_control;
|
||||
write_register(Register::CLKControl_Base + n, _clock_control[n]);
|
||||
}
|
||||
|
||||
void enable_clock(const size_t n) {
|
||||
_clock_control[n] &= ~ClockControl::CLK_PDN_Mask;
|
||||
_clock_control[n].CLK_PDN = ClockControl::ClockPowerDown::Power_On;
|
||||
write_register(Register::CLKControl_Base + n, _clock_control[n]);
|
||||
}
|
||||
|
||||
void disable_clock(const size_t n) {
|
||||
_clock_control[n] |= ClockControl::CLK_PDN_Mask;
|
||||
_clock_control[n].CLK_PDN = ClockControl::ClockPowerDown::Power_Off;
|
||||
write_register(Register::CLKControl_Base + n, _clock_control[n]);
|
||||
}
|
||||
|
||||
@@ -401,21 +468,26 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<uint8_t, 8> _clock_control;
|
||||
ClockControls _clock_control;
|
||||
I2C& _bus;
|
||||
const I2C::address_t _address;
|
||||
uint8_t _output_enable;
|
||||
|
||||
uint8_t device_status() {
|
||||
return read_register(Register::DeviceStatus);
|
||||
}
|
||||
|
||||
void update_output_enable_control() {
|
||||
write_register(Register::OutputEnableControl, ~_output_enable);
|
||||
}
|
||||
|
||||
void update_all_clock_control() {
|
||||
write_registers(Register::CLKControl_Base, _clock_control);
|
||||
write_registers(Register::CLKControl_Base, std::array<reg_t, 8> { {
|
||||
_clock_control[0],
|
||||
_clock_control[1],
|
||||
_clock_control[2],
|
||||
_clock_control[3],
|
||||
_clock_control[4],
|
||||
_clock_control[5],
|
||||
_clock_control[6],
|
||||
_clock_control[7],
|
||||
} });
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -100,53 +100,16 @@ bool get_ext_clock() {
|
||||
|
||||
void poll_ext_clock() {
|
||||
auto clkin_status = clock_generator.clkin_status();
|
||||
|
||||
|
||||
if (clkin_status != prev_clkin_status) {
|
||||
prev_clkin_status = clkin_status;
|
||||
StatusRefreshMessage message { };
|
||||
EventDispatcher::send_message(message);
|
||||
clock_manager.init();
|
||||
clock_manager.init_peripherals();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class Power {
|
||||
public:
|
||||
void init() {
|
||||
/* VAA powers:
|
||||
* MAX5864 analog section.
|
||||
* MAX2837 registers and other functions.
|
||||
* RFFC5072 analog section.
|
||||
*
|
||||
* Beware that power applied to pins of the MAX2837 may
|
||||
* show up on VAA and start powering other components on the
|
||||
* VAA net. So turn on VAA before driving pins from MCU to
|
||||
* MAX2837.
|
||||
*/
|
||||
/* Turn on VAA */
|
||||
gpio_vaa_disable.clear();
|
||||
gpio_vaa_disable.output();
|
||||
|
||||
/* 1V8 powers CPLD internals.
|
||||
*/
|
||||
/* Turn on 1V8 */
|
||||
gpio_1v8_enable.set();
|
||||
gpio_1v8_enable.output();
|
||||
|
||||
/* Set VREGMODE for switching regulator on HackRF One */
|
||||
gpio_vregmode.set();
|
||||
gpio_vregmode.output();
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
gpio_1v8_enable.clear();
|
||||
gpio_vaa_disable.set();
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
static Power power;
|
||||
|
||||
enum class PortaPackModel {
|
||||
R1_20150901,
|
||||
@@ -187,6 +150,25 @@ Backlight* backlight() {
|
||||
: static_cast<portapack::Backlight*>(&backlight_on_off);
|
||||
}
|
||||
|
||||
static void configure_unused_mcu_peripherals_power_down(const bool power_down) {
|
||||
LPC_CGU->IDIVD_CTRL.PD = power_down;
|
||||
LPC_CGU->IDIVE_CTRL.PD = power_down;
|
||||
|
||||
LPC_CGU->BASE_USB1_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_SPI_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_PHY_RX_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_PHY_TX_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_LCD_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_SSP0_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_UART0_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_UART1_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_UART2_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_UART3_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_OUT_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_CGU_OUT0_CLK.PD = power_down;
|
||||
LPC_CGU->BASE_CGU_OUT1_CLK.PD = power_down;
|
||||
}
|
||||
|
||||
static void configure_unused_mcu_peripherals(const bool enabled) {
|
||||
/* Disabling these peripherals reduces "idle" (PortaPack at main
|
||||
* menu) current by 42mA.
|
||||
@@ -196,9 +178,17 @@ static void configure_unused_mcu_peripherals(const bool enabled) {
|
||||
*
|
||||
* RITIMER: M0 SysTick substitute (because M0 has no SysTick)
|
||||
* TIMER3: M0 cycle/PCLK counter
|
||||
* IDIVB: Clock for SPI (set up in bootstrap code)
|
||||
* IDIVC: I2S audio clock
|
||||
*/
|
||||
|
||||
const uint32_t clock_run_state = enabled ? 1 : 0;
|
||||
const bool power_down = !enabled;
|
||||
|
||||
if( power_down == false ) {
|
||||
// Power up peripheral clocks *before* enabling run state.
|
||||
configure_unused_mcu_peripherals_power_down(power_down);
|
||||
}
|
||||
|
||||
LPC_CCU1->CLK_APB3_I2C1_CFG.RUN = clock_run_state;
|
||||
LPC_CCU1->CLK_APB3_DAC_CFG.RUN = clock_run_state;
|
||||
@@ -230,6 +220,11 @@ static void configure_unused_mcu_peripherals(const bool enabled) {
|
||||
LPC_CCU2->CLK_APB0_UART1_CFG.RUN = clock_run_state;
|
||||
LPC_CCU2->CLK_APB0_USART0_CFG.RUN = clock_run_state;
|
||||
LPC_CCU2->CLK_APB0_SSP0_CFG.RUN = clock_run_state;
|
||||
|
||||
if( power_down == true ) {
|
||||
// Power down peripheral clocks *after* disabling run state.
|
||||
configure_unused_mcu_peripherals_power_down(power_down);
|
||||
}
|
||||
}
|
||||
|
||||
static void disable_unused_mcu_peripheral_clocks() {
|
||||
@@ -243,9 +238,6 @@ static void enable_unused_mcu_peripheral_clocks() {
|
||||
static void shutdown_base() {
|
||||
clock_manager.shutdown();
|
||||
|
||||
power.shutdown();
|
||||
// TODO: Wait a bit for supplies to discharge?
|
||||
|
||||
chSysDisable();
|
||||
|
||||
systick_stop();
|
||||
@@ -256,49 +248,8 @@ static void shutdown_base() {
|
||||
}
|
||||
|
||||
bool init() {
|
||||
for(const auto& pin : pins) {
|
||||
pin.init();
|
||||
}
|
||||
clock_manager.init_peripherals();
|
||||
|
||||
/* Configure other pins */
|
||||
/* Glitch filter operates at 3ns instead of 50ns due to the WM8731
|
||||
* returning an ACK very fast (170ns) and confusing the I2C state
|
||||
* machine into thinking there was a bus error. It looks like the
|
||||
* MCU sees SDA fall before SCL falls, indicating a START at the
|
||||
* point an ACK is expected. With the glitch filter off or set to
|
||||
* 3ns, it's probably still a bit tight timing-wise, but improves
|
||||
* reliability on some problem units.
|
||||
*/
|
||||
LPC_SCU->SFSI2C0 =
|
||||
(1U << 0) // SCL: 3ns glitch
|
||||
| (0U << 2) // SCL: Standard/Fast mode
|
||||
| (1U << 3) // SCL: Input enabled
|
||||
| (0U << 7) // SCL: Enable input glitch filter
|
||||
| (1U << 8) // SDA: 3ns glitch
|
||||
| (0U << 10) // SDA: Standard/Fast mode
|
||||
| (1U << 11) // SDA: Input enabled
|
||||
| (0U << 15) // SDA: Enable input glitch filter
|
||||
;
|
||||
|
||||
disable_unused_mcu_peripheral_clocks();
|
||||
|
||||
LPC_CREG->CREG0 |= (1 << 5); // Disable USB0 PHY
|
||||
|
||||
power.init();
|
||||
|
||||
gpio_max5864_select.set();
|
||||
gpio_max5864_select.output();
|
||||
|
||||
gpio_max2837_select.set();
|
||||
gpio_max2837_select.output();
|
||||
|
||||
led_usb.setup();
|
||||
led_rx.setup();
|
||||
led_tx.setup();
|
||||
|
||||
clock_manager.init();
|
||||
clock_manager.set_reference_ppb(persistent_memory::correction_ppb());
|
||||
clock_manager.run_at_full_speed();
|
||||
|
||||
if( !portapack::cpld::update_if_necessary(portapack_cpld_config()) ) {
|
||||
shutdown_base();
|
||||
@@ -311,6 +262,9 @@ bool init() {
|
||||
|
||||
portapack::io.init();
|
||||
|
||||
clock_manager.init_clock_generator();
|
||||
clock_manager.set_reference_ppb(persistent_memory::correction_ppb());
|
||||
|
||||
audio::init(portapack_audio_codec());
|
||||
|
||||
clock_manager.enable_first_if_clock();
|
||||
@@ -340,12 +294,109 @@ void shutdown() {
|
||||
shutdown_base();
|
||||
}
|
||||
|
||||
/* Bootstrap runs from SPIFI on the M4, immediately after the LPC43xx built-in
|
||||
* boot ROM runs.
|
||||
*/
|
||||
|
||||
/* After boot ROM executes:
|
||||
* PLL1 is at 288MHz (IRC * 24)
|
||||
* IDIVB_CTRL = PLL1 / 9 = 32MHz
|
||||
* IDIVC_CTRL = PLL1 / 3 = 96MHz
|
||||
* BASE_SPIFI_CLK.CLK_SEL = IDIVB
|
||||
* BASE_M4_CLK.CLK_SEL = IDIVC?
|
||||
*/
|
||||
|
||||
static void configure_spifi(void) {
|
||||
constexpr Pin pins_spifi[] = {
|
||||
{ 3, 3, PinConfig::spifi_sck(3) }, /* SPIFI_SCK: W25Q80BV.CLK(I), enable input buffer for timing feedback */
|
||||
{ 3, 4, PinConfig::spifi_inout(3) }, /* SPIFI_SIO3/P82: W25Q80BV.HOLD(IO) */
|
||||
{ 3, 5, PinConfig::spifi_inout(3) }, /* SPIFI_SIO2/P81: W25Q80BV.WP(IO) */
|
||||
{ 3, 6, PinConfig::spifi_inout(3) }, /* SPIFI_MISO: W25Q80BV.DO(IO) */
|
||||
{ 3, 7, PinConfig::spifi_inout(3) }, /* SPIFI_MOSI: W25Q80BV.DI(IO) */
|
||||
{ 3, 8, PinConfig::spifi_cs(3) }, /* SPIFI_CS/P68: W25Q80BV.CS(I) */
|
||||
};
|
||||
|
||||
for(const auto& pin : pins_spifi) {
|
||||
pin.init();
|
||||
}
|
||||
|
||||
/* Tweak SPIFI mode */
|
||||
LPC_SPIFI->CTRL =
|
||||
(0xffff << 0) /* Timeout */
|
||||
| (0x1 << 16) /* CS high time in "clocks - 1" */
|
||||
| (0 << 21) /* 0: Attempt speculative prefetch on data accesses */
|
||||
| (0 << 22) /* 0: No interrupt on command ended */
|
||||
| (0 << 23) /* 0: SCK driven low after rising edge at which last bit of command is captured. Stays low while CS# is high. */
|
||||
| (0 << 27) /* 0: Cache prefetching enabled */
|
||||
| (0 << 28) /* 0: Quad protocol, IO3:0 */
|
||||
| (1 << 29) /* 1: Read data sampled on falling edge of clock */
|
||||
| (1 << 30) /* 1: Read data is sampled using feedback clock from SCK pin */
|
||||
| (0 << 31) /* 0: DMA request disabled */
|
||||
;
|
||||
|
||||
/* Throttle up the SPIFI interface to 96MHz (IDIVA=PLL1 / 3) */
|
||||
LPC_CGU->IDIVB_CTRL.word =
|
||||
( 0 << 0) /* PD */
|
||||
| ( 2 << 2) /* IDIV (/3) */
|
||||
| ( 1 << 11) /* AUTOBLOCK */
|
||||
| ( 9 << 24) /* PLL1 */
|
||||
;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void __early_init(void) {
|
||||
/*
|
||||
* Upon exit from bootloader into SPIFI boot mode:
|
||||
*
|
||||
* Enabled:
|
||||
* PLL1: IRC, M=/24, N=/1, P=/1, autoblock, direct = 288 MHz
|
||||
* IDIVA: IRC /1 = 12 MHz
|
||||
* IDIVB: PLL1 /9, autoblock = 32 MHz
|
||||
* IDIVC: PLL1 /3, autoblock = 96 MHz
|
||||
* IDIVD: IRC /1 = 12 MHz
|
||||
* IDIVE: IRC /1 = 12 MHz
|
||||
* BASE_M4_CLK: IDIVC, autoblock
|
||||
* BASE_SPIFI_CLK: IDIVB, autoblock
|
||||
*
|
||||
* Disabled:
|
||||
* XTAL_OSC
|
||||
* PLL0USB
|
||||
* PLL0AUDIO
|
||||
*/
|
||||
/* LPC43xx M4 takes about 500 usec to get to __early_init
|
||||
* Before __early_init, LPC bootloader runs and starts our code. In user code, the process stack
|
||||
* is initialized, hardware floating point is initialized, and stacks are zeroed,
|
||||
*/
|
||||
const uint32_t CORTEX_M4_CPUID = 0x410fc240;
|
||||
const uint32_t CORTEX_M4_CPUID_MASK = 0xff0ffff0;
|
||||
|
||||
if( (SCB->CPUID & CORTEX_M4_CPUID_MASK) == CORTEX_M4_CPUID ) {
|
||||
/* Enable unaligned exception handler */
|
||||
SCB_CCR |= (1 << 3);
|
||||
|
||||
/* Enable MemManage, BusFault, UsageFault exception handlers */
|
||||
SCB_SHCSR |= (1 << 18) | (1 << 17) | (1 << 16);
|
||||
|
||||
reset();
|
||||
|
||||
// disable_unused_mcu_peripheral_clocks();
|
||||
configure_spifi();
|
||||
|
||||
LPC_CCU1->CLK_M4_M0APP_CFG.RUN = true;
|
||||
LPC_CREG->M0APPMEMMAP = LPC_SPIFI_DATA_CACHED_BASE + 0x0;
|
||||
LPC_RGU->RESET_CTRL[1] = 0;
|
||||
|
||||
/* Prevent the M4 from doing any more initializing by sleep-waiting forever...
|
||||
* ...until the M0 resets the M4 with some code to run.
|
||||
*/
|
||||
while(1) {
|
||||
__WFE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __late_init(void) {
|
||||
|
||||
reset();
|
||||
|
||||
/*
|
||||
* System initializations.
|
||||
* - HAL initialization, this also initializes the configured device drivers
|
||||
|
@@ -250,9 +250,14 @@ FrequencyOptionsView::FrequencyOptionsView(
|
||||
add_children({
|
||||
&text_step,
|
||||
&field_step,
|
||||
&field_ppm,
|
||||
&text_ppm,
|
||||
});
|
||||
|
||||
if( portapack::clock_manager.get_reference_source() == ClockManager::ReferenceSource::External ) {
|
||||
add_child(&text_ext);
|
||||
} else {
|
||||
add_child(&field_ppm);
|
||||
}
|
||||
add_child(&text_ppm);
|
||||
}
|
||||
|
||||
void FrequencyOptionsView::set_step(rf::Frequency f) {
|
||||
|
@@ -293,7 +293,10 @@ private:
|
||||
1,
|
||||
'0',
|
||||
};
|
||||
|
||||
Text text_ext {
|
||||
{ 23 * 8, 0 * 16, 3 * 8, 1 * 16 },
|
||||
"EXT",
|
||||
};
|
||||
Text text_ppm {
|
||||
{ 27 * 8, 0 * 16, 3 * 8, 16 },
|
||||
"PPM",
|
||||
|
@@ -1,212 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
#
|
||||
# This file is part of PortaPack.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
# Build global options
|
||||
# NOTE: Can be overridden externally.
|
||||
#
|
||||
|
||||
enable_language(C CXX ASM)
|
||||
|
||||
project(bootstrap)
|
||||
|
||||
# Compiler options here.
|
||||
set(USE_OPT "-Os -g -falign-functions=16 -fno-math-errno --specs=nano.specs")
|
||||
|
||||
# C specific options here (added to USE_OPT).
|
||||
set(USE_COPT "-std=gnu99")
|
||||
|
||||
# C++ specific options here (added to USE_OPT).
|
||||
set(USE_CPPOPT "-std=c++17 -fno-rtti -fno-exceptions -Weffc++ -Wuninitialized")
|
||||
|
||||
# Enable this if you want the linker to remove unused code and data
|
||||
set(USE_LINK_GC yes)
|
||||
|
||||
# Linker extra options here.
|
||||
set(USE_LDOPT)
|
||||
|
||||
# Enable this if you want link time optimizations (LTO)
|
||||
set(USE_LTO no)
|
||||
|
||||
# If enabled, this option allows to compile the application in THUMB mode.
|
||||
set(USE_THUMB yes)
|
||||
|
||||
# Enable this if you want to see the full log while compiling.
|
||||
set(USE_VERBOSE_COMPILE no)
|
||||
|
||||
#
|
||||
# Build global options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Architecture or project specific options
|
||||
#
|
||||
|
||||
# Enables the use of FPU on Cortex-M4 (no, softfp, hard).
|
||||
set(USE_FPU no)
|
||||
|
||||
#
|
||||
# Architecture or project specific options
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Project, sources and paths
|
||||
#
|
||||
|
||||
# Define linker script file here
|
||||
set(LDSCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/m4.ld)
|
||||
|
||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
set(CSRC
|
||||
bootstrap.c
|
||||
)
|
||||
|
||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||
# setting.
|
||||
set(CPPSRC)
|
||||
|
||||
# C sources to be compiled in ARM mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(ACSRC)
|
||||
|
||||
# C++ sources to be compiled in ARM mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(ACPPSRC)
|
||||
|
||||
# C sources to be compiled in THUMB mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(TCSRC)
|
||||
|
||||
# C sources to be compiled in THUMB mode regardless of the global setting.
|
||||
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||
# option that results in lower performance and larger code size.
|
||||
set(TCPPSRC)
|
||||
|
||||
# List ASM source files here
|
||||
set(ASMSRC startup_ARMCM4.S)
|
||||
|
||||
set(INCDIR
|
||||
${CHIBIOS}/os/ports/common/ARMCMx/CMSIS/include
|
||||
${CHIBIOS}/os/ports/common/ARMCMx
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M4
|
||||
)
|
||||
|
||||
#
|
||||
# Project, sources and paths
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Compiler settings
|
||||
#
|
||||
|
||||
set(MCU cortex-m4)
|
||||
|
||||
# ARM-specific options here
|
||||
set(AOPT)
|
||||
|
||||
# THUMB-specific options here
|
||||
set(TOPT "-mthumb -DTHUMB")
|
||||
|
||||
# Define C warning options here
|
||||
set(CWARN "-Wall -Wextra -Wstrict-prototypes")
|
||||
|
||||
# Define C++ warning options here
|
||||
set(CPPWARN "-Wall -Wextra")
|
||||
|
||||
#
|
||||
# Compiler settings
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Start of default section
|
||||
#
|
||||
|
||||
# List all default C defines here, like -D_DEBUG=1
|
||||
# TODO: Switch -DCRT0_INIT_DATA depending on load from RAM or SPIFI?
|
||||
# NOTE: _RANDOM_TCC to kill a GCC 4.9.3 error with std::max argument types
|
||||
set(DDEFS -DLPC43XX -DLPC43XX_M4 -D__START=main -DGIT_REVISION=\"${GIT_REVISION}\")
|
||||
|
||||
# List all default ASM defines here, like -D_DEBUG=1
|
||||
set(DADEFS)
|
||||
|
||||
# List all default directories to look for include files here
|
||||
set(DINCDIR)
|
||||
|
||||
# List the default directory to look for the libraries here
|
||||
set(DLIBDIR)
|
||||
|
||||
# List all default libraries here
|
||||
set(DLIBS)
|
||||
|
||||
#
|
||||
# End of default section
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# Start of user section
|
||||
#
|
||||
|
||||
# List all user C define here, like -D_DEBUG=1
|
||||
set(UDEFS)
|
||||
|
||||
# Define ASM defines here
|
||||
set(UADEFS)
|
||||
|
||||
# List all user directories here
|
||||
set(UINCDIR)
|
||||
|
||||
# List the user directory to look for the libraries here
|
||||
set(ULIBDIR)
|
||||
|
||||
# List all user libraries here
|
||||
set(ULIBS)
|
||||
|
||||
#
|
||||
# End of user defines
|
||||
##############################################################################
|
||||
|
||||
set(RULESPATH ${CHIBIOS}/os/ports/GCC/ARMCMx)
|
||||
include(${RULESPATH}/rules.cmake)
|
||||
|
||||
##############################################################################
|
||||
|
||||
add_executable(${PROJECT_NAME}.elf ${CSRC} ${CPPSRC} ${ASMSRC})
|
||||
set_target_properties(${PROJECT_NAME}.elf PROPERTIES LINK_DEPENDS ${LDSCRIPT})
|
||||
add_definitions(${DEFS})
|
||||
include_directories(. ${INCDIR})
|
||||
link_directories(${LLIBDIR})
|
||||
target_link_libraries(${PROJECT_NAME}.elf ${LIBS})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_NAME}.bin
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
|
||||
DEPENDS ${PROJECT_NAME}.elf
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
bootstrap
|
||||
DEPENDS ${PROJECT_NAME}.bin
|
||||
)
|
Binary file not shown.
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* 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 <lpc43xx_m4.h>
|
||||
#include <nvic.h>
|
||||
|
||||
/* Bootstrap runs from SPIFI on the M4, immediately after the LPC43xx built-in
|
||||
* boot ROM runs.
|
||||
*/
|
||||
|
||||
/* After boot ROM executes:
|
||||
* PLL1 is at 288MHz (IRC * 24)
|
||||
* IDIVB_CTRL = PLL1 / 9 = 32MHz
|
||||
* IDIVC_CTRL = PLL1 / 3 = 96MHz
|
||||
* BASE_SPIFI_CLK.CLK_SEL = IDIVB
|
||||
*/
|
||||
|
||||
/* SPIFI config must run from RAM because SPIFI memory mode may/must be
|
||||
* re-initialized during the transition
|
||||
*/
|
||||
/* An ARM veneer will be created to make the long jump between code in the
|
||||
* SPIFI address range and the RAM address range.
|
||||
*/
|
||||
__attribute__ ((section("fast")))
|
||||
void configure_spifi(void) {
|
||||
/* Configure pins first, to enable SCK input buffer for feedback */
|
||||
|
||||
/* Configure SPIFI pins for maximum I/O rate */
|
||||
const uint32_t scu_spifi_io =
|
||||
(3 << 0) /* Function 3 */
|
||||
| (0 << 3) /* Disable pull-down */
|
||||
| (1 << 4) /* Disable pull-up */
|
||||
| (1 << 5) /* Fast slew rate */
|
||||
| (1 << 6) /* Enable input buffer */
|
||||
| (1 << 7) /* Disable input glitch filter */
|
||||
;
|
||||
LPC_SCU->SFSP3_3 = scu_spifi_io;
|
||||
LPC_SCU->SFSP3_4 = scu_spifi_io;
|
||||
LPC_SCU->SFSP3_5 = scu_spifi_io;
|
||||
LPC_SCU->SFSP3_6 = scu_spifi_io;
|
||||
LPC_SCU->SFSP3_7 = scu_spifi_io;
|
||||
LPC_SCU->SFSP3_8 = scu_spifi_io;
|
||||
|
||||
/* Tweak SPIFI mode */
|
||||
LPC_SPIFI->CTRL =
|
||||
(0xffff << 0) /* Timeout */
|
||||
| (0x1 << 16) /* CS high time in "clocks - 1" */
|
||||
| (0 << 21) /* 0: Attempt speculative prefetch on data accesses */
|
||||
| (0 << 22) /* 0: No interrupt on command ended */
|
||||
| (0 << 23) /* 0: SCK driven low after rising edge at which last bit of command is captured. Stays low while CS# is high. */
|
||||
| (0 << 27) /* 0: Cache prefetching enabled */
|
||||
| (0 << 28) /* 0: Quad protocol, IO3:0 */
|
||||
| (1 << 29) /* 1: Read data sampled on falling edge of clock */
|
||||
| (1 << 30) /* 1: Read data is sampled using feedback clock from SCK pin */
|
||||
| (0 << 31) /* 0: DMA request disabled */
|
||||
;
|
||||
|
||||
/* Throttle up the SPIFI interface to 96MHz (PLL1 / 3) */
|
||||
LPC_CGU->IDIVB_CTRL =
|
||||
(0 << 0) /* PD */
|
||||
| (1 << 2) /* IDIV (/2) */
|
||||
| (1 << 11) /* AUTOBLOCK */
|
||||
| (9 << 24) /* PLL1 */
|
||||
;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
#if 0
|
||||
/* Configure LEDs and make sure they're off to start */
|
||||
LPC_SCU->SFSP4_1 = (1 << 4) | 0; /* GPIO2[1] */
|
||||
LPC_SCU->SFSP4_2 = (1 << 4) | 0; /* GPIO2[2] */
|
||||
LPC_SCU->SFSP6_12 = (1 << 4) | 0; /* GPIO2[8] */
|
||||
LPC_GPIO->CLR[2] = (1 << 8) | (1 << 2) | (1 << 1);
|
||||
LPC_GPIO->DIR[2] = (1 << 8) | (1 << 2) | (1 << 1);
|
||||
|
||||
/* Indicate M4 is working */
|
||||
LPC_GPIO->SET[2] = (1 << 2);
|
||||
#endif
|
||||
configure_spifi();
|
||||
|
||||
LPC_CREG->M0APPMEMMAP = LPC_SPIFI_DATA_CACHED_BASE + 0x80000;
|
||||
|
||||
LPC_RGU->RESET_CTRL[1] = 0;
|
||||
|
||||
while(1) {
|
||||
__WFE();
|
||||
}
|
||||
}
|
||||
|
||||
void SystemInit(void) {
|
||||
}
|
Binary file not shown.
@@ -1,194 +0,0 @@
|
||||
/* Linker script to configure memory regions.
|
||||
* Need modifying for a specific board.
|
||||
* FLASH.ORIGIN: starting address of flash
|
||||
* FLASH.LENGTH: length of flash
|
||||
* RAM.ORIGIN: starting address of RAM bank 0
|
||||
* RAM.LENGTH: length of RAM bank 0
|
||||
*/
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx ) : ORIGIN = 0x00000000, LENGTH = 32k
|
||||
RAM (rwx) : ORIGIN = 0x10000000, LENGTH = 96k
|
||||
}
|
||||
|
||||
/* Linker script to place sections and symbol values. Should be used together
|
||||
* with other linker script that defines memory regions FLASH and RAM.
|
||||
* It references following symbols, which must be defined in code:
|
||||
* Reset_Handler : Entry of reset handler
|
||||
*
|
||||
* It defines following symbols, which code can use without definition:
|
||||
* __exidx_start
|
||||
* __exidx_end
|
||||
* __copy_table_start__
|
||||
* __copy_table_end__
|
||||
* __zero_table_start__
|
||||
* __zero_table_end__
|
||||
* __etext
|
||||
* __data_start__
|
||||
* __preinit_array_start
|
||||
* __preinit_array_end
|
||||
* __init_array_start
|
||||
* __init_array_end
|
||||
* __fini_array_start
|
||||
* __fini_array_end
|
||||
* __data_end__
|
||||
* __bss_start__
|
||||
* __bss_end__
|
||||
* __end__
|
||||
* end
|
||||
* __HeapLimit
|
||||
* __StackLimit
|
||||
* __StackTop
|
||||
* __stack
|
||||
*/
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.isr_vector))
|
||||
*(.text*)
|
||||
|
||||
KEEP(*(.init))
|
||||
KEEP(*(.fini))
|
||||
|
||||
/* .ctors */
|
||||
*crtbegin.o(.ctors)
|
||||
*crtbegin?.o(.ctors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
|
||||
*(SORT(.ctors.*))
|
||||
*(.ctors)
|
||||
|
||||
/* .dtors */
|
||||
*crtbegin.o(.dtors)
|
||||
*crtbegin?.o(.dtors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
|
||||
*(SORT(.dtors.*))
|
||||
*(.dtors)
|
||||
|
||||
*(.rodata*)
|
||||
|
||||
KEEP(*(.eh_frame*))
|
||||
} > FLASH
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > FLASH
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > FLASH
|
||||
__exidx_end = .;
|
||||
|
||||
/* To copy multiple ROM to RAM sections,
|
||||
* uncomment .copy.table section and,
|
||||
* define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.copy.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__copy_table_start__ = .;
|
||||
LONG (__etext)
|
||||
LONG (__data_start__)
|
||||
LONG (__data_end__ - __data_start__)
|
||||
LONG (__etext2)
|
||||
LONG (__data2_start__)
|
||||
LONG (__data2_end__ - __data2_start__)
|
||||
__copy_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
/* To clear multiple BSS sections,
|
||||
* uncomment .zero.table section and,
|
||||
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.zero.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__zero_table_start__ = .;
|
||||
LONG (__bss_start__)
|
||||
LONG (__bss_end__ - __bss_start__)
|
||||
LONG (__bss2_start__)
|
||||
LONG (__bss2_end__ - __bss2_start__)
|
||||
__zero_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
__etext = .;
|
||||
|
||||
.data : AT (__etext)
|
||||
{
|
||||
__data_start__ = .;
|
||||
/* Text/code sections that need to be located in RAM */
|
||||
*(fast)
|
||||
|
||||
*(vtable)
|
||||
*(.data*)
|
||||
|
||||
. = ALIGN(4);
|
||||
/* preinit data */
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP(*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* init data */
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP(*(SORT(.init_array.*)))
|
||||
KEEP(*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
|
||||
|
||||
. = ALIGN(4);
|
||||
/* finit data */
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP(*(SORT(.fini_array.*)))
|
||||
KEEP(*(.fini_array))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
|
||||
KEEP(*(.jcr*))
|
||||
. = ALIGN(4);
|
||||
/* All data end */
|
||||
__data_end__ = .;
|
||||
|
||||
} > RAM
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
} > RAM
|
||||
|
||||
.heap (COPY):
|
||||
{
|
||||
__end__ = .;
|
||||
PROVIDE(end = .);
|
||||
*(.heap*)
|
||||
__HeapLimit = .;
|
||||
} > RAM
|
||||
|
||||
/* .stack_dummy section doesn't contains any symbols. It is only
|
||||
* used for linker to calculate size of stack sections, and assign
|
||||
* values to stack symbols later */
|
||||
.stack_dummy (COPY):
|
||||
{
|
||||
*(.stack*)
|
||||
} > RAM
|
||||
|
||||
/* Set stack top to end of RAM, and stack limit move down by
|
||||
* size of stack_dummy section */
|
||||
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
|
||||
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
|
||||
PROVIDE(__stack = __StackTop);
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
|
||||
}
|
@@ -1,257 +0,0 @@
|
||||
/* File: startup_ARMCM4.S
|
||||
* Purpose: startup file for Cortex-M4 devices. Should use with
|
||||
* GCC for ARM Embedded Processors
|
||||
* Version: V2.0
|
||||
* Date: 16 August 2013
|
||||
*
|
||||
/* Copyright (c) 2011 - 2013 ARM LIMITED
|
||||
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
- Neither the name of ARM nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
*
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------*/
|
||||
.syntax unified
|
||||
.arch armv7e-m
|
||||
|
||||
.section .stack
|
||||
.align 3
|
||||
#ifdef __STACK_SIZE
|
||||
.equ Stack_Size, __STACK_SIZE
|
||||
#else
|
||||
.equ Stack_Size, 0xc00
|
||||
#endif
|
||||
.globl __StackTop
|
||||
.globl __StackLimit
|
||||
__StackLimit:
|
||||
.space Stack_Size
|
||||
.size __StackLimit, . - __StackLimit
|
||||
__StackTop:
|
||||
.size __StackTop, . - __StackTop
|
||||
|
||||
.section .heap
|
||||
.align 3
|
||||
#ifdef __HEAP_SIZE
|
||||
.equ Heap_Size, __HEAP_SIZE
|
||||
#else
|
||||
.equ Heap_Size, 0
|
||||
#endif
|
||||
.globl __HeapBase
|
||||
.globl __HeapLimit
|
||||
__HeapBase:
|
||||
.if Heap_Size
|
||||
.space Heap_Size
|
||||
.endif
|
||||
.size __HeapBase, . - __HeapBase
|
||||
__HeapLimit:
|
||||
.size __HeapLimit, . - __HeapLimit
|
||||
|
||||
.section .isr_vector
|
||||
.align 2
|
||||
.globl __isr_vector
|
||||
__isr_vector:
|
||||
.long __StackTop /* Top of Stack */
|
||||
.long Reset_Handler /* Reset Handler */
|
||||
.long NMI_Handler /* NMI Handler */
|
||||
.long HardFault_Handler /* Hard Fault Handler */
|
||||
.long MemManage_Handler /* MPU Fault Handler */
|
||||
.long BusFault_Handler /* Bus Fault Handler */
|
||||
.long UsageFault_Handler /* Usage Fault Handler */
|
||||
.long 0 /* Reserved */
|
||||
.long 0 /* Reserved */
|
||||
.long 0 /* Reserved */
|
||||
.long 0 /* Reserved */
|
||||
.long SVC_Handler /* SVCall Handler */
|
||||
.long DebugMon_Handler /* Debug Monitor Handler */
|
||||
.long 0 /* Reserved */
|
||||
.long PendSV_Handler /* PendSV Handler */
|
||||
.long SysTick_Handler /* SysTick Handler */
|
||||
|
||||
/* External interrupts */
|
||||
.long Default_Handler
|
||||
|
||||
.size __isr_vector, . - __isr_vector
|
||||
|
||||
.text
|
||||
.thumb
|
||||
.thumb_func
|
||||
.align 2
|
||||
.globl Reset_Handler
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
/* Firstly it copies data from read only memory to RAM. There are two schemes
|
||||
* to copy. One can copy more than one sections. Another can only copy
|
||||
* one section. The former scheme needs more instructions and read-only
|
||||
* data to implement than the latter.
|
||||
* Macro __STARTUP_COPY_MULTIPLE is used to choose between two schemes. */
|
||||
|
||||
#ifdef __STARTUP_COPY_MULTIPLE
|
||||
/* Multiple sections scheme.
|
||||
*
|
||||
* Between symbol address __copy_table_start__ and __copy_table_end__,
|
||||
* there are array of triplets, each of which specify:
|
||||
* offset 0: LMA of start of a section to copy from
|
||||
* offset 4: VMA of start of a section to copy to
|
||||
* offset 8: size of the section to copy. Must be multiply of 4
|
||||
*
|
||||
* All addresses must be aligned to 4 bytes boundary.
|
||||
*/
|
||||
ldr r4, =__copy_table_start__
|
||||
ldr r5, =__copy_table_end__
|
||||
|
||||
.L_loop0:
|
||||
cmp r4, r5
|
||||
bge .L_loop0_done
|
||||
ldr r1, [r4]
|
||||
ldr r2, [r4, #4]
|
||||
ldr r3, [r4, #8]
|
||||
|
||||
.L_loop0_0:
|
||||
subs r3, #4
|
||||
ittt ge
|
||||
ldrge r0, [r1, r3]
|
||||
strge r0, [r2, r3]
|
||||
bge .L_loop0_0
|
||||
|
||||
adds r4, #12
|
||||
b .L_loop0
|
||||
|
||||
.L_loop0_done:
|
||||
#else
|
||||
/* Single section scheme.
|
||||
*
|
||||
* The ranges of copy from/to are specified by following symbols
|
||||
* __etext: LMA of start of the section to copy from. Usually end of text
|
||||
* __data_start__: VMA of start of the section to copy to
|
||||
* __data_end__: VMA of end of the section to copy to
|
||||
*
|
||||
* All addresses must be aligned to 4 bytes boundary.
|
||||
*/
|
||||
ldr r1, =__etext
|
||||
ldr r2, =__data_start__
|
||||
ldr r3, =__data_end__
|
||||
|
||||
.L_loop1:
|
||||
cmp r2, r3
|
||||
ittt lt
|
||||
ldrlt r0, [r1], #4
|
||||
strlt r0, [r2], #4
|
||||
blt .L_loop1
|
||||
#endif /*__STARTUP_COPY_MULTIPLE */
|
||||
|
||||
/* This part of work usually is done in C library startup code. Otherwise,
|
||||
* define this macro to enable it in this startup.
|
||||
*
|
||||
* There are two schemes too. One can clear multiple BSS sections. Another
|
||||
* can only clear one section. The former is more size expensive than the
|
||||
* latter.
|
||||
*
|
||||
* Define macro __STARTUP_CLEAR_BSS_MULTIPLE to choose the former.
|
||||
* Otherwise efine macro __STARTUP_CLEAR_BSS to choose the later.
|
||||
*/
|
||||
#ifdef __STARTUP_CLEAR_BSS_MULTIPLE
|
||||
/* Multiple sections scheme.
|
||||
*
|
||||
* Between symbol address __copy_table_start__ and __copy_table_end__,
|
||||
* there are array of tuples specifying:
|
||||
* offset 0: Start of a BSS section
|
||||
* offset 4: Size of this BSS section. Must be multiply of 4
|
||||
*/
|
||||
ldr r3, =__zero_table_start__
|
||||
ldr r4, =__zero_table_end__
|
||||
|
||||
.L_loop2:
|
||||
cmp r3, r4
|
||||
bge .L_loop2_done
|
||||
ldr r1, [r3]
|
||||
ldr r2, [r3, #4]
|
||||
movs r0, 0
|
||||
|
||||
.L_loop2_0:
|
||||
subs r2, #4
|
||||
itt ge
|
||||
strge r0, [r1, r2]
|
||||
bge .L_loop2_0
|
||||
|
||||
adds r3, #8
|
||||
b .L_loop2
|
||||
.L_loop2_done:
|
||||
#elif defined (__STARTUP_CLEAR_BSS)
|
||||
/* Single BSS section scheme.
|
||||
*
|
||||
* The BSS section is specified by following symbols
|
||||
* __bss_start__: start of the BSS section.
|
||||
* __bss_end__: end of the BSS section.
|
||||
*
|
||||
* Both addresses must be aligned to 4 bytes boundary.
|
||||
*/
|
||||
ldr r1, =__bss_start__
|
||||
ldr r2, =__bss_end__
|
||||
|
||||
movs r0, 0
|
||||
.L_loop3:
|
||||
cmp r1, r2
|
||||
itt lt
|
||||
strlt r0, [r1], #4
|
||||
blt .L_loop3
|
||||
#endif /* __STARTUP_CLEAR_BSS_MULTIPLE || __STARTUP_CLEAR_BSS */
|
||||
|
||||
#ifndef __NO_SYSTEM_INIT
|
||||
bl SystemInit
|
||||
#endif
|
||||
|
||||
#ifndef __START
|
||||
#define __START _start
|
||||
#endif
|
||||
bl __START
|
||||
|
||||
.pool
|
||||
.size Reset_Handler, . - Reset_Handler
|
||||
|
||||
.align 1
|
||||
.thumb_func
|
||||
.weak Default_Handler
|
||||
.type Default_Handler, %function
|
||||
Default_Handler:
|
||||
b .
|
||||
.size Default_Handler, . - Default_Handler
|
||||
|
||||
/* Macro to define default handlers. Default handler
|
||||
* will be weak symbol and just dead loops. They can be
|
||||
* overwritten by other handlers */
|
||||
.macro def_irq_handler handler_name
|
||||
.weak \handler_name
|
||||
.set \handler_name, Default_Handler
|
||||
.endm
|
||||
|
||||
def_irq_handler NMI_Handler
|
||||
def_irq_handler HardFault_Handler
|
||||
def_irq_handler MemManage_Handler
|
||||
def_irq_handler BusFault_Handler
|
||||
def_irq_handler UsageFault_Handler
|
||||
def_irq_handler SVC_Handler
|
||||
def_irq_handler DebugMon_Handler
|
||||
def_irq_handler PendSV_Handler
|
||||
def_irq_handler SysTick_Handler
|
||||
def_irq_handler DEF_IRQHandler
|
||||
|
||||
.end
|
@@ -24,20 +24,293 @@
|
||||
* @details Digital I/O ports static configuration as defined in @p board.h.
|
||||
* This variable is used by the HAL when initializing the PAL driver.
|
||||
*/
|
||||
/**
|
||||
* CoolRunner (HackRF) CPLD:
|
||||
* CoolRunner-II devices have internal pull-ups on TDI, TMS, and TCK.
|
||||
* It is not necessary to externally terminate JTAG pins with internal termination; they can be
|
||||
* left floating. External pull-ups on pins with internal termination is allowed, but not
|
||||
* necessary. External pull-down termination is not recommended as it would conflict with
|
||||
* the internal pull-ups
|
||||
*
|
||||
* LPC43xx pull-ups come on line when 3V3 supply voltage reaches about 2V.
|
||||
*
|
||||
* 3V3 supply:
|
||||
* Ramps up in about 1ms.
|
||||
*
|
||||
* 1V8 supply:
|
||||
* Ramps up in about 1ms.
|
||||
* EN1V8 has a 10K pull-down on the HackRF and is pulled up (very gently) by the LPC43xx
|
||||
* bootloader at boot time. So until the EN1V8 pin is reconfigured as an output, the enable
|
||||
* pin on the 1V8 supply sits at about 0.55V, which feels untidy...
|
||||
* 1V8 supply is activated when GPIO is driven high by user code.
|
||||
*/
|
||||
const PALConfig pal_default_config = {
|
||||
.P = {
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{
|
||||
.data = 0,
|
||||
.dir = (1 << 8) | (1 << 2) | (1 << 1)
|
||||
{ // GPIO0
|
||||
.data
|
||||
= (1 << 15) // CS_XCVR
|
||||
| (1 << 14) // AMP_BYPASS
|
||||
| (0 << 9) // 10K PD, BOOT1
|
||||
| (1 << 8) // 10K PU, BOOT0
|
||||
,
|
||||
.dir
|
||||
= (1 << 15) // CS_XCVR
|
||||
| (1 << 14) // AMP_BYPASS
|
||||
| (0 << 9) // 10K PD, BOOT1
|
||||
| (0 << 8) // 10K PU, BOOT0
|
||||
},
|
||||
{ // GPIO1
|
||||
.data
|
||||
= (1 << 13) // PortaPack P2_13/DIR
|
||||
| (1 << 12) // !RX_AMP_PWR
|
||||
| (0 << 11) // RX_AMP
|
||||
| (1 << 10) // 10K PD, BOOT3, PortaPack P2_9/LCD_WRX
|
||||
| (1 << 8) // PortaPack CPLD.TDO(O)
|
||||
| (1 << 1) // PortaPack CPLD.TMS(I)
|
||||
| (0 << 0) // !MIX_BYPASS
|
||||
,
|
||||
.dir
|
||||
= (1 << 13) // PortaPack P2_13/DIR
|
||||
| (1 << 12) // !RX_AMP_PWR
|
||||
| (1 << 11) // RX_AMP
|
||||
| (1 << 10) // 10K PD, BOOT3, PortaPack P2_9/LCD_WRX
|
||||
| (0 << 8) // PortaPack CPLD.TDO(O) (input with pull up)
|
||||
| (0 << 1) // PortaPack CPLD.TMS(I) (output only when needed, pull up internal to CPLD)
|
||||
| (1 << 0) // !MIX_BYPASS
|
||||
},
|
||||
{ // GPIO2
|
||||
.data
|
||||
= (0 << 15) // TX_AMP
|
||||
| (0 << 11) // TX_MIX_BP
|
||||
| (1 << 14) // MIXER_RESETX, 10K PU
|
||||
| (1 << 13) // MIXER_ENX, 10K PU
|
||||
| (1 << 12) // RX_MIX_BP
|
||||
| (0 << 10) // LP
|
||||
| (1 << 9) // !VAA_ENABLE
|
||||
| (0 << 8) // LED3 (TX)
|
||||
| (1 << 7) // CS_AD
|
||||
| (0 << 6) // XCVR_EN, 10K PD
|
||||
| (0 << 5) // RXENABLE
|
||||
| (0 << 4) // TXENABLE
|
||||
| (0 << 2) // LED2 (RX)
|
||||
| (0 << 1) // LED1 (USB)
|
||||
| (1 << 0) // HP
|
||||
,
|
||||
.dir
|
||||
= (1 << 15) // TX_AMP
|
||||
| (1 << 14) // MIXER_RESETX, 10K PU
|
||||
| (1 << 13) // MIXER_ENX, 10K PU
|
||||
| (1 << 12) // RX_MIX_BP
|
||||
| (1 << 11) // TX_MIX_BP
|
||||
| (1 << 10) // LP
|
||||
| (1 << 9) // !VAA_ENABLE
|
||||
| (1 << 8) // LED3 (TX)
|
||||
| (1 << 7) // CS_AD
|
||||
| (1 << 6) // XCVR_EN, 10K PD
|
||||
| (1 << 5) // RXENABLE
|
||||
| (1 << 4) // TXENABLE
|
||||
| (1 << 2) // LED2 (RX)
|
||||
| (1 << 1) // LED1 (USB)
|
||||
| (1 << 0) // HP
|
||||
},
|
||||
{ // GPIO3
|
||||
.data
|
||||
= (0 << 15) // PortaPack GPIO3_15(IO)
|
||||
| (0 << 14) // PortaPack GPIO3_14(IO)
|
||||
| (0 << 13) // PortaPack GPIO3_13(IO)
|
||||
| (0 << 12) // PortaPack GPIO3_12(IO)
|
||||
| (0 << 11) // PortaPack GPIO3_11(IO)
|
||||
| (0 << 10) // PortaPack GPIO3_10(IO)
|
||||
| (0 << 9) // PortaPack GPIO3_9(IO)
|
||||
| (0 << 8) // PortaPack GPIO3_8(IO)
|
||||
| (0 << 7) // VREGMODE
|
||||
| (1 << 6) // EN1V8, 10K PD
|
||||
| (1 << 5) // !TX_AMP_PWR, 10K PU
|
||||
| (1 << 4) // HackRF CPLD.TMS(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
|
||||
| (1 << 1) // HackRF CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
|
||||
| (1 << 0) // HackRF CPLD.TCK(I), PortaPack CPLD.TCK(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
|
||||
,
|
||||
.dir
|
||||
= (0 << 15) // PortaPack GPIO3_15(IO)
|
||||
| (0 << 14) // PortaPack GPIO3_14(IO)
|
||||
| (0 << 13) // PortaPack GPIO3_13(IO)
|
||||
| (0 << 12) // PortaPack GPIO3_12(IO)
|
||||
| (0 << 11) // PortaPack GPIO3_11(IO)
|
||||
| (0 << 10) // PortaPack GPIO3_10(IO)
|
||||
| (0 << 9) // PortaPack GPIO3_9(IO)
|
||||
| (0 << 8) // PortaPack GPIO3_8(IO)
|
||||
| (1 << 7) // VREGMODE
|
||||
| (1 << 6) // EN1V8, 10K PD
|
||||
| (1 << 5) // !TX_AMP_PWR, 10K PU
|
||||
| (0 << 4) // HackRF CPLD.TMS(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
|
||||
| (0 << 1) // HackRF CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
|
||||
| (0 << 0) // HackRF CPLD.TCK(I), PortaPack CPLD.TCK(I) (output only when needed, pull-up internal to CPLD when 1V8 present)
|
||||
},
|
||||
{ // GPIO4
|
||||
.data = 0,
|
||||
.dir = 0
|
||||
},
|
||||
{ // GPIO5
|
||||
.data
|
||||
= (1 << 18) // HackRF CPLD.TDO(O) (input with pull up)
|
||||
| (0 << 15) // TX
|
||||
| (1 << 16) // MIX_BYPASS
|
||||
| (1 << 5) // RX
|
||||
| (1 << 4) // PortaPack P2_4/LCD_RDX
|
||||
| (0 << 3) // PortaPack P2_3/LCD_TE
|
||||
| (0 << 1) // PortaPack P2_1/ADDR
|
||||
| (1 << 0) // PortaPack P2_0/IO_STBX
|
||||
,
|
||||
.dir
|
||||
= (0 << 18) // HackRF CPLD.TDO(O) (input with pull up)
|
||||
| (1 << 16) // MIX_BYPASS
|
||||
| (1 << 15) // TX
|
||||
| (1 << 5) // RX
|
||||
| (1 << 4) // PortaPack P2_4/LCD_RDX
|
||||
| (0 << 3) // PortaPack P2_3/LCD_TE
|
||||
| (1 << 1) // PortaPack P2_1/ADDR
|
||||
| (1 << 0) // PortaPack P2_0/IO_STBX
|
||||
},
|
||||
{ // GPIO6
|
||||
.data = 0,
|
||||
.dir = 0
|
||||
},
|
||||
{ // GPIO7
|
||||
.data = 0,
|
||||
.dir = 0
|
||||
},
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
},
|
||||
.SCU = {
|
||||
/* Configure GP_CLKIN as soon as possible. It's an output at boot time, and the Si5351C doesn't
|
||||
* reset when the reset button is pressed, so it could still be output enabled.
|
||||
*/
|
||||
{ 4, 7, .config={ .MODE=1, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=1 } }, /* GP_CLKIN/P72/MCU_CLK: SI5351C.CLK7(O) */
|
||||
|
||||
/* HackRF: LEDs. Configured early so we can use them to indicate boot status. */
|
||||
{ 4, 1, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* LED1: LED1.A(I) */
|
||||
{ 4, 2, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* LED2: LED2.A(I) */
|
||||
{ 6, 12, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* LED3: LED3.A(I) */
|
||||
|
||||
/* Power control */
|
||||
{ 5, 0, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* !VAA_ENABLE: 10K PU, Q3.G(I), power to VAA */
|
||||
{ 6, 10, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* EN1V8/P70: 10K PD, TPS62410.EN2(I), 1V8LED.A(I) */
|
||||
{ 6, 11, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* VREGMODE/P69: TPS62410.MODE/DATA(I) */
|
||||
|
||||
/* HackRF: I2C0 */
|
||||
/* Glitch filter operates at 3ns instead of 50ns due to the WM8731
|
||||
* returning an ACK very fast (170ns) and confusing the I2C state
|
||||
* machine into thinking there was a bus error. It looks like the
|
||||
* MCU sees SDA fall before SCL falls, indicating a START at the
|
||||
* point an ACK is expected. With the glitch filter off or set to
|
||||
* 3ns, it's probably still a bit tight timing-wise, but improves
|
||||
* reliability on some problem units.
|
||||
*/
|
||||
{ 25, 1,
|
||||
.config = {
|
||||
.word = // SFSI2C0
|
||||
(1U << 0) // SCL: 3ns glitch
|
||||
| (0U << 2) // SCL: Standard/Fast mode
|
||||
| (1U << 3) // SCL: Input enabled
|
||||
| (0U << 7) // SCL: Enable input glitch filter
|
||||
| (1U << 8) // SDA: 3ns glitch
|
||||
| (0U << 10) // SDA: Standard/Fast mode
|
||||
| (1U << 11) // SDA: Input enabled
|
||||
| (0U << 15) // SDA: Enable input glitch filter
|
||||
}
|
||||
},
|
||||
|
||||
/* Radio section control */
|
||||
{ 1, 3, .config={ .MODE=5, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* SSP1_MISO/P41: MAX2837.DOUT(O) */
|
||||
{ 1, 4, .config={ .MODE=5, .EPD=1, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* SSP1_MOSI/P40: MAX2837.DIN(I), MAX5864.DIN(I) */
|
||||
{ 1, 7, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* !MIX_BYPASS/P35: U1.VCTL1(I), U11.VCTL2(I), U9.V2(I) */
|
||||
{ 1, 19, .config={ .MODE=1, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* SSP1_SCK/P39: MAX2837.SCLK(I), MAX5864.SCLK(I) */
|
||||
{ 1, 20, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* CS_XCVR/P53: MAX2837.CS(I) */
|
||||
{ 2, 5, .config={ .MODE=4, .EPD=0, .EPUN=0, .EHS=0, .EZI=0, .ZIF=0 } }, /* RX/P43: U7.VCTL1(I), U10.VCTL1(I), U2.VCTL1(I) */
|
||||
{ 2, 6, .config={ .MODE=4, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* MIXER_SCLK/P31: 33pF, RFFC5072.SCLK(I) */
|
||||
{ 2, 10, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* AMP_BYPASS/P50: U14.V2(I), U12.V2(I) */
|
||||
{ 2, 11, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* RX_AMP/P49: U12.V1(I), U14.V3(I) */
|
||||
{ 2, 12, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* !RX_AMP_PWR/P52: 10K PU, Q1.G(I), power to U13 (RX amp) */
|
||||
{ 4, 0, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* HP/P44: U6.VCTL1(I), U5.VCTL2(I) */
|
||||
{ 4, 4, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* TXENABLE/P55: MAX2837.TXENABLE(I) */
|
||||
{ 4, 5, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* RXENABLE/P56: MAX2837.RXENABLE(I) */
|
||||
{ 4, 6, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* XCVR_EN: 10K PD, MAX2837.ENABLE(I) */
|
||||
{ 5, 1, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* LP/P45: U6.VCTL2(I), U5.VCTL1(I) */
|
||||
{ 5, 2, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* TX_MIX_BP/P46: U9.V1(I) */
|
||||
{ 5, 3, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* RX_MIX_BP/P47: U9.V3(I) */
|
||||
{ 5, 4, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* MIXER_ENX/P32: 10K PU, 33pF, RFFC5072.ENX(I) */
|
||||
{ 5, 5, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* MIXER_RESETX/P33: 10K PU, 33pF, RFFC5072.RESETX(I) */
|
||||
{ 5, 6, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* TX_AMP/P48: U12.V3(I), U14.V1(I) */
|
||||
{ 5, 7, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* CS_AD/P54: MAX5864.CS(I) */
|
||||
{ 6, 4, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* MIXER_SDATA/P27: 33pF, RFFC5072.SDATA(IO) */
|
||||
{ 6, 7, .config={ .MODE=4, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* TX/P42: U7.VCTL2(I), U10.VCTL2(I), U2.VCTL2(I) */
|
||||
{ 6, 8, .config={ .MODE=4, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* MIX_BYPASS/P34: U1.VCTL2(I), U11.VCTL1(I) */
|
||||
{ 6, 9, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* !TX_AMP_PWR/P51: 10K PU, Q2.G(I), power to U25 (TX amp) */
|
||||
|
||||
/* SGPIO for sample transfer interface to HackRF CPLD. */
|
||||
{ 0, 0, .config={ .MODE=3, .EPD=0, .EPUN=1, .EHS=1, .EZI=1, .ZIF=1 } }, /* SGPIO0/P75/BANK2F3M3: CPLD.89/HOST_DATA0(IO) */
|
||||
{ 0, 1, .config={ .MODE=3, .EPD=0, .EPUN=1, .EHS=1, .EZI=1, .ZIF=1 } }, /* SGPIO1/BANK2F3M5: CPLD.79/HOST_DATA1(IO) */
|
||||
{ 1, 15, .config={ .MODE=2, .EPD=0, .EPUN=1, .EHS=1, .EZI=1, .ZIF=1 } }, /* SGPIO2/BANK2F3M9: CPLD.74/HOST_DATA2(IO) */
|
||||
{ 1, 16, .config={ .MODE=2, .EPD=0, .EPUN=1, .EHS=1, .EZI=1, .ZIF=1 } }, /* SGPIO3/BANK2F3M10: CPLD.72/HOST_DATA3(IO) */
|
||||
{ 6, 3, .config={ .MODE=2, .EPD=0, .EPUN=1, .EHS=1, .EZI=1, .ZIF=1 } }, /* SGPIO4/BANK2F3M14: CPLD.67/HOST_DATA4(IO) */
|
||||
{ 6, 6, .config={ .MODE=2, .EPD=0, .EPUN=1, .EHS=1, .EZI=1, .ZIF=1 } }, /* SGPIO5/BANK2F3M15: CPLD.64/HOST_DATA5(IO) */
|
||||
{ 2, 2, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=1, .EZI=1, .ZIF=1 } }, /* SGPIO6/BANK2F3M16: CPLD.61/HOST_DATA6(IO) */
|
||||
{ 1, 0, .config={ .MODE=6, .EPD=0, .EPUN=1, .EHS=1, .EZI=1, .ZIF=1 } }, /* SGPIO7/P76/BANK2F3M7: CPLD.77/HOST_DATA7(IO) */
|
||||
{ 9, 6, .config={ .MODE=6, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=1 } }, /* SGPIO8/SGPIO_CLK/P60: SI5351C.CLK2(O) */
|
||||
{ 4, 3, .config={ .MODE=7, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=1 } }, /* SGPIO9/P77/BANK2F3M1: CPLD.91/HOST_CAPTURE(O) */
|
||||
{ 1, 14, .config={ .MODE=6, .EPD=0, .EPUN=0, .EHS=1, .EZI=0, .ZIF=0 } }, /* SGPIO10/P78/BANK2F3M8: CPLD.76/HOST_DISABLE(I) */
|
||||
{ 1, 17, .config={ .MODE=6, .EPD=0, .EPUN=0, .EHS=1, .EZI=0, .ZIF=0 } }, /* SGPIO11/P79/BANK2F3M11: CPLD.71/HOST_DIRECTION(I) */
|
||||
{ 1, 18, .config={ .MODE=0, .EPD=1, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* SGPIO12/BANK2F3M12: CPLD.70/HOST_INVERT(I) */
|
||||
{ 4, 8, .config={ .MODE=4, .EPD=0, .EPUN=0, .EHS=0, .EZI=0, .ZIF=0 } }, /* SGPIO13/BANK2F3M2: CPLD.90/HOST_DECIM_SEL0(I) */
|
||||
{ 4, 9, .config={ .MODE=4, .EPD=0, .EPUN=0, .EHS=0, .EZI=0, .ZIF=0 } }, /* SGPIO14/BANK2F3M4: CPLD.81/HOST_DECIM_SEL1(I) */
|
||||
{ 4, 10, .config={ .MODE=4, .EPD=0, .EPUN=0, .EHS=0, .EZI=0, .ZIF=0 } }, /* SGPIO15/BANK2F3M6: CPLD.78/HOST_DECIM_SEL2(I) */
|
||||
|
||||
/* HackRF: CPLD */
|
||||
{ 6, 1, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* CPLD_TCK: CPLD.TCK(I), PortaPack CPLD.TCK(I) */
|
||||
{ 6, 2, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* CPLD_TDI: CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) */
|
||||
{ 6, 5, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* CPLD_TMS: CPLD.TMS(I) */
|
||||
{ 9, 5, .config={ .MODE=4, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* CPLD_TDO: CPLD.TDO(O) */
|
||||
|
||||
/* PortaPack */
|
||||
{ 1, 5, .config={ .MODE=0, .EPD=0, .EPUN=0, .EHS=0, .EZI=1, .ZIF=0 } }, /* SD_POW: PortaPack CPLD.TDO(O) */
|
||||
{ 1, 8, .config={ .MODE=0, .EPD=0, .EPUN=0, .EHS=0, .EZI=0, .ZIF=0 } }, /* SD_VOLT0: PortaPack CPLD.TMS(I) */
|
||||
{ 2, 0, .config={ .MODE=4, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* U0_TXD: PortaPack P2_0/IO_STBX */
|
||||
{ 2, 1, .config={ .MODE=4, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* U0_RXD: PortaPack P2_1/ADDR */
|
||||
{ 2, 3, .config={ .MODE=4, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* I2C1_SDA: PortaPack P2_3/LCD_TE */
|
||||
{ 2, 4, .config={ .MODE=4, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* I2C1_SCL: PortaPack P2_4/LCD_RDX */
|
||||
{ 2, 8, .config={ .MODE=4, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* P2_8: 10K PD, BOOT2, DFU switch, PortaPack P2_8/<unused> */
|
||||
{ 2, 9, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* P2_9: 10K PD, BOOT3, PortaPack P2_9/LCD_WRX */
|
||||
{ 2, 13, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* P2_13: PortaPack P2_13/DIR */
|
||||
{ 7, 0, .config={ .MODE=0, .EPD=1, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* GPIO3_8: PortaPack GPIO3_8(IO) */
|
||||
{ 7, 1, .config={ .MODE=0, .EPD=1, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* GPIO3_9: PortaPack GPIO3_9(IO) */
|
||||
{ 7, 2, .config={ .MODE=0, .EPD=1, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* GPIO3_10: PortaPack GPIO3_10(IO) */
|
||||
{ 7, 3, .config={ .MODE=0, .EPD=1, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* GPIO3_11: PortaPack GPIO3_11(IO) */
|
||||
{ 7, 4, .config={ .MODE=0, .EPD=1, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* GPIO3_12: PortaPack GPIO3_12(IO) */
|
||||
{ 7, 5, .config={ .MODE=0, .EPD=1, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* GPIO3_13: PortaPack GPIO3_13(IO) */
|
||||
{ 7, 6, .config={ .MODE=0, .EPD=1, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* GPIO3_14: PortaPack GPIO3_14(IO) */
|
||||
{ 7, 7, .config={ .MODE=0, .EPD=1, .EPUN=1, .EHS=0, .EZI=1, .ZIF=0 } }, /* GPIO3_15: PortaPack GPIO3_15(IO) */
|
||||
|
||||
/* PortaPack: Audio */
|
||||
{ 3, 0, .config={ .MODE=2, .EPD=0, .EPUN=0, .EHS=0, .EZI=1, .ZIF=0 } }, /* I2S0_TX_SCK: PortaPack I2S0_TX_SCK(I) */
|
||||
{ 3, 1, .config={ .MODE=0, .EPD=0, .EPUN=0, .EHS=0, .EZI=1, .ZIF=0 } }, /* I2S0_RX_WS: PortaPack I2S0_TX_WS(I). Input enabled to fold back into RX. */
|
||||
{ 3, 2, .config={ .MODE=0, .EPD=0, .EPUN=0, .EHS=0, .EZI=0, .ZIF=0 } }, /* I2S0_RX_SDA: PortaPack I2S0_TX_SDA(I) */
|
||||
{ 24, 2, .config={ .MODE=6, .EPD=1, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* I2S0_TX_CLK: PortaPack I2S0_TX_MCLK */
|
||||
|
||||
/* PortaPack: SD card socket */
|
||||
{ 24, 0, .config={ .MODE=4, .EPD=1, .EPUN=1, .EHS=0, .EZI=1, .ZIF=1 } }, /* SD_CLK: PortaPack SD.CLK, enable input buffer for timing feedback? */
|
||||
{ 1, 6, .config={ .MODE=7, .EPD=0, .EPUN=0, .EHS=0, .EZI=1, .ZIF=1 } }, /* SD_CMD: PortaPack SD.CMD(IO) */
|
||||
{ 1, 9, .config={ .MODE=7, .EPD=0, .EPUN=0, .EHS=0, .EZI=1, .ZIF=1 } }, /* SD_DAT0: PortaPack SD.DAT0(IO) */
|
||||
{ 1, 10, .config={ .MODE=7, .EPD=0, .EPUN=0, .EHS=0, .EZI=1, .ZIF=1 } }, /* SD_DAT1: PortaPack SD.DAT1(IO) */
|
||||
{ 1, 11, .config={ .MODE=7, .EPD=0, .EPUN=0, .EHS=0, .EZI=1, .ZIF=1 } }, /* SD_DAT2: PortaPack SD.DAT2(IO) */
|
||||
{ 1, 12, .config={ .MODE=7, .EPD=0, .EPUN=0, .EHS=0, .EZI=1, .ZIF=1 } }, /* SD_DAT3: PortaPack SD.DAT3(IO) */
|
||||
{ 1, 13, .config={ .MODE=7, .EPD=0, .EPUN=0, .EHS=0, .EZI=1, .ZIF=0 } }, /* SD_CD: PortaPack SD.CD(O) */
|
||||
|
||||
/* Miscellaneous */
|
||||
{ 1, 1, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* P1_1/P74: 10K PU, BOOT0 */
|
||||
{ 1, 2, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* P1_2/P73: 10K PD, BOOT1 */
|
||||
{ 2, 7, .config={ .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 } }, /* ISP: 10K PU, Unused */
|
||||
{ 6, 0, .config={ .MODE=0, .EPD=0, .EPUN=0, .EHS=0, .EZI=0, .ZIF=0 } }, /* I2S0_RX_MCLK: Unused */
|
||||
{ 15, 4, .config={ .MODE=7, .EPD=0, .EPUN=0, .EHS=0, .EZI=0, .ZIF=0 } }, /* I2S0_RX_SCK: Unused */
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
Copyright (C) 2014 Jared Boone, ShareBrained Technology
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_PAL || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief PAL setup.
|
||||
* @details Digital I/O ports static configuration as defined in @p board.h.
|
||||
* This variable is used by the HAL when initializing the PAL driver.
|
||||
*/
|
||||
const PALConfig pal_default_config = {
|
||||
.P = {
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
{ .data = 0, .dir = 0 },
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Early initialization code.
|
||||
* @details This initialization must be performed just after stack setup
|
||||
* and before any other initialization.
|
||||
*/
|
||||
// void __early_init(void) {
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Board-specific initialization code.
|
||||
* @todo Add your board-specific code, if any.
|
||||
*/
|
||||
void boardInit(void) {
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
|
||||
Copyright (C) 2015 Jared Boone, ShareBrained Technology
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
/*
|
||||
* Setup for ShareBrained PortaPack H1 Tester
|
||||
*/
|
||||
|
||||
/*
|
||||
* Board identifiers.
|
||||
*/
|
||||
#define BOARD_SHAREBRAINED_PP_H1_TEST
|
||||
#define BOARD_NAME "ShareBrained PortaPack H1 Tester"
|
||||
|
||||
#if !defined(_FROM_ASM_)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void boardInit(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _FROM_ASM_ */
|
||||
|
||||
#endif /* _BOARD_H_ */
|
@@ -1,5 +0,0 @@
|
||||
# List of all the board related files.
|
||||
BOARDSRC = ${CHIBIOS_PORTAPACK}/boards/SHAREBRAINED_PP_H1_TEST/board.c
|
||||
|
||||
# Required include directories
|
||||
BOARDINC = ${CHIBIOS_PORTAPACK}/boards/SHAREBRAINED_PP_H1_TEST
|
@@ -54,6 +54,24 @@ ADCDriver ADCD1;
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if LPC43XX_ADC_USE_ADC0
|
||||
static const adc_resources_t adc0_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_APB3_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1U << 0) },
|
||||
.branch = { .cfg = &LPC_CCU1->CLK_APB3_ADC0_CFG, .stat = &LPC_CCU1->CLK_APB3_ADC0_STAT },
|
||||
.reset = { .output_index = 40 },
|
||||
.interrupt = { .irq = ADC0_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_ADC0_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif /* LPC43XX_ADC_USE_ADC0 */
|
||||
|
||||
#if LPC43XX_ADC_USE_ADC1
|
||||
static const adc_resources_t adc1_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_APB3_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1U << 0) },
|
||||
.branch = { .cfg = &LPC_CCU1->CLK_APB3_ADC1_CFG, .stat = &LPC_CCU1->CLK_APB3_ADC1_STAT },
|
||||
.reset = { .output_index = 41 },
|
||||
.interrupt = { .irq = ADC1_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_ADC1_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif /* LPC43XX_ADC_USE_ADC1 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
@@ -129,6 +147,7 @@ void adc_lld_init(void) {
|
||||
adcObjectInit(&ADCD0);
|
||||
/* TODO: Implement */
|
||||
ADCD0.adc = LPC_ADC0;
|
||||
ADCD0.resources = &adc0_resources;
|
||||
#endif /* LPC43XX_ADC_USE_ADC0 */
|
||||
|
||||
#if LPC43XX_ADC_USE_ADC1
|
||||
@@ -136,6 +155,7 @@ void adc_lld_init(void) {
|
||||
adcObjectInit(&ADCD1);
|
||||
/* TODO: Implement */
|
||||
ADCD1.adc = LPC_ADC1;
|
||||
ADCD1.resources = &adc1_resources;
|
||||
#endif /* LPC43XX_ADC_USE_ADC1 */
|
||||
}
|
||||
|
||||
@@ -150,20 +170,10 @@ void adc_lld_start(ADCDriver *adcp) {
|
||||
|
||||
if (adcp->state == ADC_STOP) {
|
||||
/* Enables the peripheral.*/
|
||||
#if LPC43XX_ADC_USE_ADC0
|
||||
if (&ADCD0 == adcp) {
|
||||
LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 1;
|
||||
LPC_CGU->BASE_APB3_CLK.PD = 0;
|
||||
nvicEnableVector(ADC0_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_ADC0_IRQ_PRIORITY));
|
||||
}
|
||||
#endif /* LPC43XX_ADC_USE_ADC0 */
|
||||
#if LPC43XX_ADC_USE_ADC1
|
||||
if (&ADCD1 == adcp) {
|
||||
LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 1;
|
||||
LPC_CGU->BASE_APB3_CLK.PD = 0;
|
||||
nvicEnableVector(ADC1_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_ADC1_IRQ_PRIORITY));
|
||||
}
|
||||
#endif /* LPC43XX_ADC_USE_ADC1 */
|
||||
base_clock_enable(&adcp->resources->base);
|
||||
branch_clock_enable(&adcp->resources->branch);
|
||||
peripheral_reset(&adcp->resources->reset);
|
||||
interrupt_enable(&adcp->resources->interrupt);
|
||||
|
||||
/* Configures the peripheral.*/
|
||||
adcp->adc->CR =
|
||||
@@ -201,21 +211,10 @@ void adc_lld_stop(ADCDriver *adcp) {
|
||||
;
|
||||
|
||||
/* Disables the peripheral.*/
|
||||
#if LPC43XX_ADC_USE_ADC0
|
||||
if (&ADCD0 == adcp) {
|
||||
nvicDisableVector(ADC0_IRQn);
|
||||
LPC_CCU1->CLK_APB3_ADC0_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 0;
|
||||
}
|
||||
#endif /* LPC43XX_ADC_USE_ADC0 */
|
||||
|
||||
#if LPC43XX_ADC_USE_ADC1
|
||||
if (&ADCD1 == adcp) {
|
||||
nvicDisableVector(ADC1_IRQn);
|
||||
LPC_CCU1->CLK_APB3_ADC1_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 0;
|
||||
}
|
||||
#endif /* LPC43XX_ADC_USE_ADC1 */
|
||||
interrupt_disable(&adcp->resources->interrupt);
|
||||
peripheral_reset(&adcp->resources->reset);
|
||||
branch_clock_disable(&adcp->resources->branch);
|
||||
base_clock_disable(&adcp->resources->base);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -95,6 +95,16 @@
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Structure used for ADC configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
base_clock_regs_t base;
|
||||
branch_clock_regs_t branch;
|
||||
peripheral_reset_t reset;
|
||||
interrupt_config_t interrupt;
|
||||
} adc_resources_t;
|
||||
|
||||
typedef LPC_ADCx_Type* ADC_TypeDef;
|
||||
|
||||
/**
|
||||
@@ -235,6 +245,10 @@ struct ADCDriver {
|
||||
* @brief Pointer to the ADCx registers block.
|
||||
*/
|
||||
ADC_TypeDef adc;
|
||||
/**
|
||||
* @brief Pointer to the non-peripheral ADC resources.
|
||||
*/
|
||||
const adc_resources_t * resources;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@@ -32,6 +32,38 @@
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if LPC43XX_GPT_USE_TIMER0
|
||||
static const timer_resources_t timer0_resources = {
|
||||
.branch = { .cfg = &LPC_CCU1->CLK_M4_TIMER0_CFG, .stat = &LPC_CCU1->CLK_M4_TIMER0_STAT },
|
||||
.reset = { .output_index = 32 },
|
||||
.interrupt = { .irq = TIMER0_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER0_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif /* LPC43XX_GPT_USE_TIMER0 */
|
||||
|
||||
#if LPC43XX_GPT_USE_TIMER1
|
||||
static const timer_resources_t timer1_resources = {
|
||||
.branch = { .cfg = &LPC_CCU1->CLK_M4_TIMER1_CFG, .stat = &LPC_CCU1->CLK_M4_TIMER1_STAT },
|
||||
.reset = { .output_index = 33 },
|
||||
.interrupt = { .irq = TIMER1_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER1_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif /* LPC43XX_GPT_USE_TIMER1 */
|
||||
|
||||
#if LPC43XX_GPT_USE_TIMER2
|
||||
static const timer_resources_t timer2_resources = {
|
||||
.branch = { .cfg = &LPC_CCU1->CLK_M4_TIMER2_CFG, .stat = &LPC_CCU1->CLK_M4_TIMER2_STAT },
|
||||
.reset = { .output_index = 34 },
|
||||
.interrupt = { .irq = TIMER2_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER2_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif /* LPC43XX_GPT_USE_TIMER3 */
|
||||
|
||||
#if LPC43XX_GPT_USE_TIMER3
|
||||
static const timer_resources_t timer3_resources = {
|
||||
.branch = { .cfg = &LPC_CCU1->CLK_M4_TIMER3_CFG, .stat = &LPC_CCU1->CLK_M4_TIMER3_STAT },
|
||||
.reset = { .output_index = 35 },
|
||||
.interrupt = { .irq = TIMER3_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER3_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif /* LPC43XX_GPT_USE_TIMER3 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
@@ -158,24 +190,28 @@ void gpt_lld_init(void) {
|
||||
/* Driver initialization.*/
|
||||
gptObjectInit(&GPTD1);
|
||||
GPTD1.tmr = LPC_TIMER0;
|
||||
GPTD1.resources = &timer0_resources;
|
||||
#endif /* LPC43XX_GPT_USE_TIMER0 */
|
||||
|
||||
#if LPC43XX_GPT_USE_TIMER1
|
||||
/* Driver initialization.*/
|
||||
gptObjectInit(&GPTD2);
|
||||
GPTD2.tmr = LPC_TIMER1;
|
||||
GPTD2.resources = &timer1_resources;
|
||||
#endif /* LPC43XX_GPT_USE_TIMER1 */
|
||||
|
||||
#if LPC43XX_GPT_USE_TIMER2
|
||||
/* Driver initialization.*/
|
||||
gptObjectInit(&GPTD3);
|
||||
GPTD3.tmr = LPC_TIMER2;
|
||||
GPTD3.resources = &timer2_resources;
|
||||
#endif /* LPC43XX_GPT_USE_TIMER2 */
|
||||
|
||||
#if LPC43XX_GPT_USE_TIMER3
|
||||
/* Driver initialization.*/
|
||||
gptObjectInit(&GPTD4);
|
||||
GPTD4.tmr = LPC_TIMER3;
|
||||
GPTD4.resources = &timer3_resources;
|
||||
#endif /* LPC43XX_GPT_USE_TIMER3 */
|
||||
}
|
||||
|
||||
@@ -190,30 +226,9 @@ void gpt_lld_start(GPTDriver *gptp) {
|
||||
|
||||
if (gptp->state == GPT_STOP) {
|
||||
/* Enables the peripheral.*/
|
||||
#if LPC43XX_GPT_USE_TIMER0
|
||||
if (&GPTD1 == gptp) {
|
||||
LPC_CCU1->CLK_M4_TIMER0_CFG.RUN = 1;
|
||||
nvicEnableVector(TIMER0_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER0_IRQ_PRIORITY));
|
||||
}
|
||||
#endif /* LPC43XX_GPT_USE_TIMER0 */
|
||||
#if LPC43XX_GPT_USE_TIMER1
|
||||
if (&GPTD2 == gptp) {
|
||||
LPC_CCU1->CLK_M4_TIMER1_CFG.RUN = 1;
|
||||
nvicEnableVector(TIMER1_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER1_IRQ_PRIORITY));
|
||||
}
|
||||
#endif /* LPC43XX_GPT_USE_TIMER1 */
|
||||
#if LPC43XX_GPT_USE_TIMER2
|
||||
if (&GPTD3 == gptp) {
|
||||
LPC_CCU1->CLK_M4_TIMER2_CFG.RUN = 1;
|
||||
nvicEnableVector(TIMER2_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER2_IRQ_PRIORITY));
|
||||
}
|
||||
#endif /* LPC43XX_GPT_USE_TIMER3 */
|
||||
#if LPC43XX_GPT_USE_TIMER3
|
||||
if (&GPTD4 == gptp) {
|
||||
LPC_CCU1->CLK_M4_TIMER3_CFG.RUN = 1;
|
||||
nvicEnableVector(TIMER3_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER3_IRQ_PRIORITY));
|
||||
}
|
||||
#endif /* LPC43XX_GPT_USE_TIMER3 */
|
||||
branch_clock_enable(&gptp->resources->branch);
|
||||
peripheral_reset(&gptp->resources->reset);
|
||||
interrupt_enable(&gptp->resources->interrupt);
|
||||
}
|
||||
|
||||
/* Timer configuration.*/
|
||||
@@ -237,34 +252,9 @@ void gpt_lld_stop(GPTDriver *gptp) {
|
||||
gptp->tmr->MCR = 0;
|
||||
gptp->tmr->TCR = 0;
|
||||
|
||||
#if LPC43XX_GPT_USE_TIMER0
|
||||
if (&GPTD1 == gptp) {
|
||||
nvicDisableVector(TIMER0_IRQn);
|
||||
LPC_CCU1->CLK_M4_TIMER0_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_M4_TIMER0_CFG.RUN = 0;
|
||||
}
|
||||
#endif /* LPC43XX_GPT_USE_TIMER0 */
|
||||
#if LPC43XX_GPT_USE_TIMER1
|
||||
if (&GPTD2 == gptp) {
|
||||
nvicDisableVector(TIMER1_IRQn);
|
||||
LPC_CCU1->CLK_M4_TIMER1_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_M4_TIMER1_CFG.RUN = 0;
|
||||
}
|
||||
#endif /* LPC43XX_GPT_USE_TIMER1 */
|
||||
#if LPC43XX_GPT_USE_TIMER2
|
||||
if (&GPTD3 == gptp) {
|
||||
nvicDisableVector(TIMER2_IRQn);
|
||||
LPC_CCU1->CLK_M4_TIMER2_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_M4_TIMER2_CFG.RUN = 0;
|
||||
}
|
||||
#endif /* LPC43XX_GPT_USE_TIMER2 */
|
||||
#if LPC43XX_GPT_USE_TIMER3
|
||||
if (&GPTD4 == gptp) {
|
||||
nvicDisableVector(TIMER3_IRQn);
|
||||
LPC_CCU1->CLK_M4_TIMER3_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_M4_TIMER3_CFG.RUN = 0;
|
||||
}
|
||||
#endif /* LPC43XX_GPT_USE_TIMER3 */
|
||||
interrupt_disable(&gptp->resources->interrupt);
|
||||
peripheral_reset(&gptp->resources->reset);
|
||||
branch_clock_disable(&gptp->resources->branch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -135,6 +135,15 @@
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Structure used for Timer configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
branch_clock_regs_t branch;
|
||||
peripheral_reset_t reset;
|
||||
interrupt_config_t interrupt;
|
||||
} timer_resources_t;
|
||||
|
||||
/**
|
||||
* @brief GPT frequency type.
|
||||
*/
|
||||
@@ -185,6 +194,10 @@ struct GPTDriver {
|
||||
* @brief Pointer to the TIMER registers block.
|
||||
*/
|
||||
LPC_TIMER_Type *tmr;
|
||||
/**
|
||||
* @brief Pointer to the non-peripheral Timer resources.
|
||||
*/
|
||||
const timer_resources_t * resources;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@@ -86,6 +86,22 @@ I2CDriver I2CD1;
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if LPC43XX_I2C_USE_I2C0
|
||||
static const i2c_resources_t i2c0_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_APB1_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 1) },
|
||||
.branch = { .cfg = &LPC_CCU1->CLK_APB1_I2C0_CFG, .stat = &LPC_CCU1->CLK_APB1_I2C0_STAT },
|
||||
.reset = { .output_index = 48 },
|
||||
};
|
||||
#endif /* LPC43XX_I2C_USE_I2C0 */
|
||||
|
||||
#if LPC43XX_I2C_USE_I2C1
|
||||
static const i2c_resources_t i2c1_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_APB3_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 0) },
|
||||
.branch = { .cfg = &LPC_CCU1->CLK_APB3_I2C1_CFG, .stat = &LPC_CCU1->CLK_APB3_I2C1_STAT },
|
||||
.reset = { .output_index = 49 },
|
||||
};
|
||||
#endif /* LPC43XX_I2C_USE_I2C1 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
@@ -364,12 +380,14 @@ void i2c_lld_init(void) {
|
||||
i2cObjectInit(&I2CD0);
|
||||
I2CD0.thread = NULL;
|
||||
I2CD0.i2c = LPC_I2C0;
|
||||
I2CD0.resources = &i2c0_resources;
|
||||
#endif /* LPC43XX_I2C_USE_I2C0 */
|
||||
|
||||
#if LPC43XX_I2C_USE_I2C1 || defined(__DOXYGEN__)
|
||||
i2cObjectInit(&I2CD1);
|
||||
I2CD1.thread = NULL;
|
||||
I2CD1.i2c = LPC_I2C1;
|
||||
I2CD1.resources = &i2c1_resources;
|
||||
#endif /* LPC43XX_I2C_USE_I2C1 */
|
||||
}
|
||||
|
||||
@@ -385,19 +403,9 @@ void i2c_lld_start(I2CDriver *i2cp) {
|
||||
|
||||
/* TODO: Reset peripheral, enable clocks? */
|
||||
|
||||
#if LPC43XX_I2C_USE_I2C0 || defined(__DOXYGEN__)
|
||||
if (&I2CD0 == i2cp) {
|
||||
////LPC_CCU1->CLK_APB1_I2C0_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_APB1_I2C0_CFG.RUN = 1;
|
||||
}
|
||||
#endif /* LPC43XX_I2C_USE_I2C0 */
|
||||
|
||||
#if LPC43XX_I2C_USE_I2C1 || defined(__DOXYGEN__)
|
||||
if (&I2CD1 == i2cp) {
|
||||
////LPC_CCU1->CLK_APB3_I2C1_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_APB3_I2C1_CFG.RUN = 1;
|
||||
}
|
||||
#endif /* LPC43XX_I2C_USE_I2C1 */
|
||||
base_clock_enable(&i2cp->resources->base);
|
||||
branch_clock_enable(&i2cp->resources->branch);
|
||||
peripheral_reset(&i2cp->resources->reset);
|
||||
|
||||
i2c_periph_set_clock(dp, i2cp->config->high_count, i2cp->config->low_count);
|
||||
i2c_periph_enable(dp);
|
||||
@@ -441,9 +449,16 @@ void i2c_lld_stop(I2CDriver *i2cp) {
|
||||
#if defined(LPC43XX_M4)
|
||||
nvicDisableVector(I2C0_IRQn);
|
||||
#endif
|
||||
i2c_periph_disable(dp);
|
||||
LPC_CCU1->CLK_APB1_I2C0_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_APB1_I2C0_CFG.RUN = 0;
|
||||
#if defined(LPC43XX_M0)
|
||||
#if LPC43XX_I2C_USE_I2C1
|
||||
if( I2CD1.state == I2C_STOP ) {
|
||||
#endif
|
||||
// TODO: This won't work if the I2C peripherals are split between cores!
|
||||
nvicDisableVector(I2C0_OR_I2C1_IRQn);
|
||||
#if LPC43XX_I2C_USE_I2C1
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif /* LPC43XX_I2C_USE_I2C0 */
|
||||
|
||||
@@ -452,11 +467,23 @@ void i2c_lld_stop(I2CDriver *i2cp) {
|
||||
#if defined(LPC43XX_M4)
|
||||
nvicDisableVector(I2C1_IRQn);
|
||||
#endif
|
||||
i2c_periph_disable(dp);
|
||||
LPC_CCU1->CLK_APB3_I2C1_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_APB3_I2C1_CFG.RUN = 0;
|
||||
#if defined(LPC43XX_M0)
|
||||
#if LPC43XX_I2C_USE_I2C0
|
||||
if( I2CD0.state == I2C_STOP ) {
|
||||
#endif
|
||||
// TODO: This won't work if the I2C peripherals are split between cores!
|
||||
nvicDisableVector(I2C0_OR_I2C1_IRQn);
|
||||
#if LPC43XX_I2C_USE_I2C0
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif /* LPC43XX_I2C_USE_I2C1 */
|
||||
|
||||
i2c_periph_disable(dp);
|
||||
peripheral_reset(&i2cp->resources->reset);
|
||||
branch_clock_disable(&i2cp->resources->branch);
|
||||
base_clock_disable(&i2cp->resources->base);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -96,6 +96,15 @@
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Structure used for I2C configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
base_clock_regs_t base;
|
||||
branch_clock_regs_t branch;
|
||||
peripheral_reset_t reset;
|
||||
} i2c_resources_t;
|
||||
|
||||
typedef LPC_I2Cx_Type* I2C_TypeDef;
|
||||
|
||||
/**
|
||||
@@ -181,6 +190,10 @@ struct I2CDriver {
|
||||
* @brief Pointer to the I2Cx registers block.
|
||||
*/
|
||||
I2C_TypeDef i2c;
|
||||
/**
|
||||
* @brief Pointer to the non-peripheral I2C resources.
|
||||
*/
|
||||
const i2c_resources_t * resources;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright (C) 2018 Jared Boone, ShareBrained Technology
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
void peripheral_reset(const peripheral_reset_t* const reset) {
|
||||
const size_t register_index = (reset->output_index >> 5) & 1;
|
||||
const size_t bit_shift = reset->output_index & 0x1f;
|
||||
const uint32_t mask = (1U << bit_shift);
|
||||
LPC_RGU->RESET_CTRL[register_index] = mask | (~LPC_RGU->RESET_ACTIVE_STATUS[register_index]);
|
||||
while((LPC_RGU->RESET_ACTIVE_STATUS[register_index] & mask) == 0);
|
||||
}
|
||||
|
||||
void base_clock_enable(const base_clock_regs_t* const base) {
|
||||
if( base->clk->PD ) {
|
||||
base->clk->AUTOBLOCK = 1;
|
||||
//base->clk->CLK_SEL = ?;
|
||||
base->clk->PD = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void base_clock_disable(const base_clock_regs_t* const base) {
|
||||
if( !base->clk->PD ) {
|
||||
// Are all branch clocks switched off?
|
||||
// NOTE: Field stat must be valid memory address.
|
||||
// NOTE: Field stat_mask is zero if there's no means to check if a base clock is in use.
|
||||
if( (*base->stat & base->stat_mask) == 0 ) {
|
||||
base->clk->PD = 1;
|
||||
//base->clk->CLK_SEL = IRC?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void branch_clock_enable(const branch_clock_regs_t* const branch) {
|
||||
if( !branch->stat->RUN ) {
|
||||
branch->cfg->AUTO = 1;
|
||||
branch->cfg->RUN = 1;
|
||||
while(!branch->stat->RUN);
|
||||
}
|
||||
}
|
||||
|
||||
void branch_clock_disable(const branch_clock_regs_t* const branch) {
|
||||
if( branch->stat->RUN ) {
|
||||
branch->cfg->RUN = 0;
|
||||
while(branch->stat->RUN);
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_enable(const interrupt_config_t* const interrupt) {
|
||||
nvicEnableVector(interrupt->irq, interrupt->priority_mask);
|
||||
}
|
||||
|
||||
void interrupt_disable(const interrupt_config_t* const interrupt) {
|
||||
nvicDisableVector(interrupt->irq);
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright (C) 2018 Jared Boone, ShareBrained Technology
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _LPC43XX_H_
|
||||
#define _LPC43XX_H_
|
||||
|
||||
typedef struct {
|
||||
LPC_CGU_BASE_CLK_Type* clk;
|
||||
__I uint32_t* stat;
|
||||
uint32_t stat_mask;
|
||||
} base_clock_regs_t;
|
||||
|
||||
typedef struct {
|
||||
LPC_CCU1_CFG_160_Type* cfg;
|
||||
LPC_CCU_STAT_Type* stat;
|
||||
} branch_clock_regs_t;
|
||||
|
||||
typedef struct {
|
||||
uint_fast8_t output_index;
|
||||
} peripheral_reset_t;
|
||||
|
||||
typedef struct {
|
||||
IRQn_Type irq;
|
||||
uint32_t priority_mask;
|
||||
} interrupt_config_t;
|
||||
|
||||
void peripheral_reset(const peripheral_reset_t* const reset);
|
||||
|
||||
void base_clock_enable(const base_clock_regs_t* const base);
|
||||
void base_clock_disable(const base_clock_regs_t* const base);
|
||||
|
||||
void branch_clock_enable(const branch_clock_regs_t* const branch);
|
||||
void branch_clock_disable(const branch_clock_regs_t* const branch);
|
||||
|
||||
void interrupt_enable(const interrupt_config_t* const interrupt);
|
||||
void interrupt_disable(const interrupt_config_t* const interrupt);
|
||||
|
||||
#endif /* _LPC43XX_H_ */
|
@@ -98,11 +98,14 @@ typedef struct {
|
||||
uint32_t RESERVED0 : 3;
|
||||
} LPC_CGU_FREQ_MON_Type;
|
||||
|
||||
typedef struct {
|
||||
__IO uint32_t ENABLE : 1;
|
||||
__IO uint32_t BYPASS : 1;
|
||||
__IO uint32_t HF : 1;
|
||||
uint32_t RESERVED0 : 29;
|
||||
typedef union {
|
||||
struct {
|
||||
__IO uint32_t ENABLE : 1;
|
||||
__IO uint32_t BYPASS : 1;
|
||||
__IO uint32_t HF : 1;
|
||||
uint32_t RESERVED0 : 29;
|
||||
};
|
||||
__IO uint32_t word;
|
||||
} LPC_CGU_XTAL_OSC_CTRL_Type;
|
||||
|
||||
typedef struct {
|
||||
@@ -146,18 +149,21 @@ typedef struct {
|
||||
__IO uint32_t CLK_SEL : 5;
|
||||
uint32_t RESERVED3 : 3;
|
||||
} LPC_CGU_PLL1_CTRL_Type;
|
||||
/*
|
||||
typedef struct {
|
||||
__IO uint32_t PD : 1;
|
||||
uint32_t RESERVED0 : 1;
|
||||
__IO uint32_t IDIV : 2;
|
||||
uint32_t RESERVED1 : 7;
|
||||
__IO uint32_t AUTOBLOCK : 1;
|
||||
uint32_t RESERVED2 : 12;
|
||||
__IO uint32_t CLK_SEL : 5;
|
||||
uint32_t RESERVED3 : 3;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
__IO uint32_t PD : 1;
|
||||
uint32_t RESERVED0 : 1;
|
||||
__IO uint32_t IDIV : 2;
|
||||
uint32_t RESERVED1 : 7;
|
||||
__IO uint32_t AUTOBLOCK : 1;
|
||||
uint32_t RESERVED2 : 12;
|
||||
__IO uint32_t CLK_SEL : 5;
|
||||
uint32_t RESERVED3 : 3;
|
||||
};
|
||||
__IO uint32_t word;
|
||||
} LPC_CGU_IDIVx_CTRL_Type;
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
__I uint32_t PD : 1;
|
||||
uint32_t RESERVED0 : 10;
|
||||
@@ -167,13 +173,16 @@ typedef struct {
|
||||
uint32_t RESERVED2 : 3;
|
||||
} LPC_CGU_BASE_SAFE_CLK_Type;
|
||||
|
||||
typedef struct {
|
||||
__IO uint32_t PD : 1;
|
||||
uint32_t RESERVED0 : 10;
|
||||
__IO uint32_t AUTOBLOCK : 1;
|
||||
uint32_t RESERVED1 : 12;
|
||||
__IO uint32_t CLK_SEL : 5;
|
||||
uint32_t RESERVED2 : 3;
|
||||
typedef union {
|
||||
struct {
|
||||
__IO uint32_t PD : 1;
|
||||
uint32_t RESERVED0 : 10;
|
||||
__IO uint32_t AUTOBLOCK : 1;
|
||||
uint32_t RESERVED1 : 12;
|
||||
__IO uint32_t CLK_SEL : 5;
|
||||
uint32_t RESERVED2 : 3;
|
||||
};
|
||||
__IO uint32_t word;
|
||||
} LPC_CGU_BASE_CLK_Type;
|
||||
|
||||
typedef struct {
|
||||
@@ -191,11 +200,11 @@ typedef struct {
|
||||
__IO uint32_t PLL0AUDIO_FRAC;
|
||||
__I uint32_t PLL1_STAT; /* +0x040 */
|
||||
__IO uint32_t PLL1_CTRL;
|
||||
__IO uint32_t IDIVA_CTRL;
|
||||
__IO uint32_t IDIVB_CTRL;
|
||||
__IO uint32_t IDIVC_CTRL; /* +0x050 */
|
||||
__IO uint32_t IDIVD_CTRL;
|
||||
__IO uint32_t IDIVE_CTRL;
|
||||
LPC_CGU_IDIVx_CTRL_Type IDIVA_CTRL;
|
||||
LPC_CGU_IDIVx_CTRL_Type IDIVB_CTRL;
|
||||
LPC_CGU_IDIVx_CTRL_Type IDIVC_CTRL; /* +0x050 */
|
||||
LPC_CGU_IDIVx_CTRL_Type IDIVD_CTRL;
|
||||
LPC_CGU_IDIVx_CTRL_Type IDIVE_CTRL;
|
||||
LPC_CGU_BASE_SAFE_CLK_Type BASE_SAFE_CLK;
|
||||
LPC_CGU_BASE_CLK_Type BASE_USB0_CLK; /* +0x060 */
|
||||
LPC_CGU_BASE_CLK_Type BASE_PERIPH_CLK;
|
||||
@@ -1065,6 +1074,47 @@ typedef struct {
|
||||
__IO uint32_t CTCR;
|
||||
} LPC_TIMER_Type;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ----- MOTOCONPWM -----
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Product name title=UM10503 Chapter title=LPC43xx Motor Control PWM (MOTOCONPWM) Modification date=7/26/2017 Major revision=2 Minor revision=3
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
__I uint32_t CON;
|
||||
__O uint32_t CON_SET;
|
||||
__O uint32_t CON_CLR;
|
||||
__I uint32_t CAPCON;
|
||||
__O uint32_t CAPCON_SET;
|
||||
__O uint32_t CAPCON_CLR;
|
||||
__IO uint32_t TC0;
|
||||
__IO uint32_t TC1;
|
||||
__IO uint32_t TC2;
|
||||
__IO uint32_t LIM0;
|
||||
__IO uint32_t LIM1;
|
||||
__IO uint32_t LIM2;
|
||||
__IO uint32_t MAT0;
|
||||
__IO uint32_t MAT1;
|
||||
__IO uint32_t MAT2;
|
||||
__IO uint32_t DT;
|
||||
__IO uint32_t MCCP;
|
||||
__I uint32_t CAP0;
|
||||
__I uint32_t CAP1;
|
||||
__I uint32_t CAP2;
|
||||
__I uint32_t INTEN;
|
||||
__O uint32_t INTEN_SET;
|
||||
__O uint32_t INTEN_CLR;
|
||||
__I uint32_t CNTCON;
|
||||
__O uint32_t CNTCON_SET;
|
||||
__O uint32_t CNTCON_CLR;
|
||||
__I uint32_t INTF;
|
||||
__O uint32_t INTF_SET;
|
||||
__O uint32_t INTF_CLR;
|
||||
__O uint32_t CAP_CLR;
|
||||
} LPC_MCPWM_Type;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ----- RITIMER -----
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -1409,6 +1459,7 @@ typedef struct {
|
||||
#define LPC_USART3 ((LPC_USART_Type *) LPC_USART3_BASE)
|
||||
#define LPC_TIMER2 ((LPC_TIMER_Type *) LPC_TIMER2_BASE)
|
||||
#define LPC_TIMER3 ((LPC_TIMER_Type *) LPC_TIMER3_BASE)
|
||||
#define LPC_MCPWM ((LPC_MCPWM_Type *) LPC_MCPWM_BASE)
|
||||
#define LPC_SSP1 ((LPC_SSPx_Type *) LPC_SSP1_BASE)
|
||||
#define LPC_I2C1 ((LPC_I2Cx_Type *) LPC_I2C1_BASE)
|
||||
#define LPC_ADC0 ((LPC_ADCx_Type *) LPC_ADC0_BASE)
|
||||
|
@@ -40,10 +40,74 @@
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static const scu_config_t pin_config_vaa_enablex_pwm = { .MODE=1, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 };
|
||||
static const scu_config_t pin_config_vaa_enablex_gpio = { .MODE=0, .EPD=0, .EPUN=1, .EHS=0, .EZI=0, .ZIF=0 };
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
|
||||
/* VAA powers:
|
||||
* MAX5864 analog section.
|
||||
* MAX2837 registers and other functions.
|
||||
* RFFC5072 analog section.
|
||||
*
|
||||
* Beware that power applied to pins of the MAX2837 may
|
||||
* show up on VAA and start powering other components on the
|
||||
* VAA net. So turn on VAA before driving pins from MCU to
|
||||
* MAX2837.
|
||||
*/
|
||||
static void vaa_power_on(void) {
|
||||
/* Very twitchy process for powering up VAA without glitching the 3.3V rail, which can send the
|
||||
* microcontroller into reset.
|
||||
*
|
||||
* Controlling timing while running from SPIFI flash is tricky, hence use of a PWM peripheral...
|
||||
*/
|
||||
|
||||
/* Configure and enable MOTOCONPWM peripheral clocks.
|
||||
* Assume IDIVC is running the post-bootloader configuration, outputting 96MHz derived from PLL1.
|
||||
*/
|
||||
LPC_CCU1->CLK_APB1_MOTOCON_PWM_CFG.RUN = true;
|
||||
|
||||
/* Combination of pulse duration and duty cycle was arrived at empirically, to keep supply glitching
|
||||
* to +/- 0.15V.
|
||||
*/
|
||||
const uint32_t cycle_period = 128;
|
||||
const uint32_t enable_period = 10;
|
||||
LPC_MCPWM->TC2 = 0;
|
||||
LPC_MCPWM->MAT2 = cycle_period - enable_period;
|
||||
LPC_MCPWM->LIM2 = cycle_period;
|
||||
|
||||
/* Switch !VAA_ENABLE pin from GPIO to MOTOCONPWM peripheral output, now that the peripheral is configured. */
|
||||
LPC_SCU->SFSP[5][ 0] = pin_config_vaa_enablex_pwm.word; // P5_0 /GPIO2[ 9]/MCOB2: !VAA_ENABLE, 10K PU
|
||||
|
||||
/* Start the PWM operation. */
|
||||
LPC_MCPWM->CON_SET = (1 << 16);
|
||||
|
||||
/* Wait until VAA rises to approximately 90% of final voltage. */
|
||||
/* Timing assumes we're running immediately after the bootloader: 96 MHz from IRC+PLL1
|
||||
*/
|
||||
{ volatile uint32_t delay = 12000; while(delay--); }
|
||||
|
||||
/* Hold !VAA_ENABLE active using a GPIO, so we can reclaim and shut down the MOTOCONPWM peripheral. */
|
||||
LPC_GPIO->CLR[2] = (1 << 9); // !VAA_ENABLE
|
||||
LPC_GPIO->DIR[2] |= (1 << 9);
|
||||
LPC_SCU->SFSP[5][ 0] = pin_config_vaa_enablex_gpio.word; // P5_0 /GPIO2[ 9]/MCOB2: !VAA_ENABLE, 10K PU
|
||||
|
||||
/* Reset the MOTOCONPWM peripheral. */
|
||||
LPC_RGU->RESET_CTRL[1] = (1U << 6);
|
||||
|
||||
/* Shut down the MOTOCONPWM clocks. */
|
||||
LPC_CCU1->CLK_APB1_MOTOCON_PWM_CFG.RUN = false;
|
||||
}
|
||||
|
||||
static void vaa_power_off(void) {
|
||||
// TODO: There's a lot of other stuff that must be done to prevent
|
||||
// leakage from +3V3 into VAA.
|
||||
LPC_GPIO->W2[9] = 1;
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
@@ -52,6 +116,8 @@
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
/**
|
||||
* @brief LPC43xx I/O ports configuration.
|
||||
* @details Ports 0 through 8.
|
||||
@@ -65,6 +131,12 @@ void _pal_lld_init(const PALConfig *config) {
|
||||
LPC_GPIO->PIN[i] = config->P[i].data;
|
||||
LPC_GPIO->DIR[i] = config->P[i].dir;
|
||||
}
|
||||
|
||||
for(size_t i=0; i<ARRAY_SIZE(config->SCU); i++) {
|
||||
LPC_SCU->SFSP[config->SCU[i].port][config->SCU[i].pin] = config->SCU[i].config.word;
|
||||
}
|
||||
|
||||
vaa_power_on();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -51,6 +51,27 @@ typedef struct {
|
||||
uint32_t dir;
|
||||
} gpio_setup_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint16_t MODE : 3;
|
||||
uint16_t EPD : 1;
|
||||
uint16_t EPUN : 1;
|
||||
uint16_t EHS : 1;
|
||||
uint16_t EZI : 1;
|
||||
uint16_t ZIF : 1;
|
||||
uint16_t RESERVED0 : 8;
|
||||
};
|
||||
uint16_t word;
|
||||
};
|
||||
} scu_config_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t port;
|
||||
uint8_t pin;
|
||||
scu_config_t config;
|
||||
} scu_setup_t;
|
||||
|
||||
/**
|
||||
* @brief Generic I/O ports static initializer.
|
||||
* @details An instance of this structure must be passed to @p palInit() at
|
||||
@@ -63,6 +84,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
/** @brief GPIO setup data.*/
|
||||
gpio_setup_t P[8];
|
||||
scu_setup_t SCU[86];
|
||||
} PALConfig;
|
||||
|
||||
/**
|
||||
|
@@ -47,6 +47,16 @@ SDCDriver SDCD1;
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if LPC_SDC_USE_SDC1
|
||||
static const sdio_resources_t sdio_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_SDIO_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = 0 },
|
||||
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_SDIO_CFG, .stat = &LPC_CCU1->CLK_M4_SDIO_STAT },
|
||||
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_SDIO_CFG, .stat = &LPC_CCU2->CLK_SDIO_STAT },
|
||||
.reset = { .output_index = 20 },
|
||||
.interrupt = { .irq = SDIO_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC_SDC_SDIO_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
@@ -561,6 +571,7 @@ CH_IRQ_HANDLER(SDIO_IRQHandler) {
|
||||
void sdc_lld_init(void) {
|
||||
|
||||
sdcObjectInit(&SDCD1);
|
||||
SDCD1.resources = &sdio_resources;
|
||||
SDCD1.thread = NULL;
|
||||
|
||||
/* Assuming there's a global reset when the hardware is initialized.
|
||||
@@ -578,10 +589,12 @@ void sdc_lld_init(void) {
|
||||
void sdc_lld_start(SDCDriver *sdcp) {
|
||||
|
||||
if (sdcp->state == BLK_STOP) {
|
||||
LPC_SDMMC->CLKENA = (1U << 16); /* CCLK_LOW_POWER */
|
||||
base_clock_enable(&sdcp->resources->base);
|
||||
branch_clock_enable(&sdcp->resources->branch_register_if);
|
||||
branch_clock_enable(&sdcp->resources->branch_peripheral);
|
||||
peripheral_reset(&sdcp->resources->reset);
|
||||
|
||||
LPC_CCU1->CLK_M4_SDIO_CFG.RUN = 1;
|
||||
LPC_CGU->BASE_SDIO_CLK.PD = 0;
|
||||
LPC_SDMMC->CLKENA = (1U << 16); /* CCLK_LOW_POWER */
|
||||
|
||||
sdio_reset();
|
||||
sdio_reset_card();
|
||||
@@ -623,8 +636,7 @@ void sdc_lld_start(SDCDriver *sdcp) {
|
||||
sdio_interrupts_set_mask(0);
|
||||
sdio_interrupts_clear();
|
||||
|
||||
nvicEnableVector(SDIO_IRQn,
|
||||
CORTEX_PRIORITY_MASK(LPC_SDC_SDIO_IRQ_PRIORITY));
|
||||
interrupt_enable(&sdcp->resources->interrupt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,7 +650,7 @@ void sdc_lld_start(SDCDriver *sdcp) {
|
||||
void sdc_lld_stop(SDCDriver *sdcp) {
|
||||
|
||||
if (sdcp->state != BLK_STOP) {
|
||||
nvicDisableVector(SDIO_IRQn);
|
||||
interrupt_disable(&sdcp->resources->interrupt);
|
||||
|
||||
/* Quickest way to return peripheral and card to known (and low power)
|
||||
* state is to reset both. Right?
|
||||
@@ -646,9 +658,10 @@ void sdc_lld_stop(SDCDriver *sdcp) {
|
||||
sdio_reset();
|
||||
sdio_reset_card();
|
||||
|
||||
LPC_CGU->BASE_SDIO_CLK.PD = 1;
|
||||
LPC_CCU1->CLK_M4_SDIO_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_M4_SDIO_CFG.RUN = 0;
|
||||
peripheral_reset(&sdcp->resources->reset);
|
||||
branch_clock_disable(&sdcp->resources->branch_peripheral);
|
||||
branch_clock_disable(&sdcp->resources->branch_register_if);
|
||||
base_clock_disable(&sdcp->resources->base);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -76,6 +76,17 @@
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Structure used for SDIO configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
base_clock_regs_t base;
|
||||
branch_clock_regs_t branch_register_if;
|
||||
branch_clock_regs_t branch_peripheral;
|
||||
peripheral_reset_t reset;
|
||||
interrupt_config_t interrupt;
|
||||
} sdio_resources_t;
|
||||
|
||||
/**
|
||||
* @brief Type of SDIO bus mode.
|
||||
*/
|
||||
@@ -149,6 +160,10 @@ struct SDCDriver {
|
||||
*/
|
||||
uint32_t rca;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Pointer to the non-peripheral SDIO resources.
|
||||
*/
|
||||
const sdio_resources_t * resources;
|
||||
/**
|
||||
* @brief Thread waiting for I/O completion IRQ.
|
||||
*/
|
||||
|
@@ -63,6 +63,48 @@ static const SerialConfig default_config = {
|
||||
FCR_TRIGGER0
|
||||
};
|
||||
|
||||
#if LPC_SERIAL_USE_USART0
|
||||
static const uart_resources_t usart0_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_UART0_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 4) },
|
||||
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_USART0_CFG, .stat = &LPC_CCU1->CLK_M4_USART0_STAT },
|
||||
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB0_USART0_CFG, .stat = &LPC_CCU2->CLK_APB0_USART0_STAT },
|
||||
.reset = { .output_index = 44 },
|
||||
.interrupt = { .irq = USART0_IRQn, priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_USART0_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif
|
||||
#if LPC_SERIAL_USE_UART1
|
||||
static const uart_resources_t uart1_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_UART1_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 3) },
|
||||
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_UART1_CFG, .stat = &LPC_CCU1->CLK_M4_UART1_STAT },
|
||||
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB0_UART1_CFG, .stat = &LPC_CCU2->CLK_APB0_UART1_STAT },
|
||||
.reset = { .output_index = 45 },
|
||||
.interrupt = { .irq = UART1_IRQn, priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_UART1_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif
|
||||
#if LPC_SERIAL_USE_USART2
|
||||
static const uart_resources_t usart2_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_UART2_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 2) },
|
||||
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_USART2_CFG, .stat = &LPC_CCU1->CLK_M4_USART2_STAT },
|
||||
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB2_USART2_CFG, .stat = &LPC_CCU2->CLK_APB2_USART2_STAT },
|
||||
.reset = { .output_index = 46 },
|
||||
#if defined(LPC43XX_M4)
|
||||
.interrupt = { .irq = USART2_IRQn, priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_USART2_IRQ_PRIORITY) },
|
||||
#endif
|
||||
#if defined(LPC43XX_M0)
|
||||
.interrupt = { .irq = USART2_OR_C_CAN1_IRQn, priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_USART2_IRQ_PRIORITY) },
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
#if LPC_SERIAL_USE_USART3
|
||||
static const uart_resources_t usart3_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_UART3_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 1) },
|
||||
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_USART3_CFG, .stat = &LPC_CCU1->CLK_M4_USART3_STAT },
|
||||
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB2_USART3_CFG, .stat = &LPC_CCU2->CLK_APB2_USART3_STAT },
|
||||
.reset = { .output_index = 47 },
|
||||
.interrupt = { .irq = USART3_IRQn, priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_USART3_IRQ_PRIORITY) },
|
||||
};
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
@@ -337,21 +379,25 @@ void sd_lld_init(void) {
|
||||
#if LPC_SERIAL_USE_USART0
|
||||
sdObjectInit(&SD1, NULL, notify1);
|
||||
SD1.uart = LPC_USART0;
|
||||
SD1.resources = &usart0_resources;
|
||||
#endif
|
||||
|
||||
#if LPC_SERIAL_USE_UART1
|
||||
sdObjectInit(&SD2, NULL, notify2);
|
||||
SD2.uart = (LPC_USART_Type *) LPC_UART1;
|
||||
SD2.resources = &uart1_resources;
|
||||
#endif
|
||||
|
||||
#if LPC_SERIAL_USE_USART2
|
||||
sdObjectInit(&SD3, NULL, notify3);
|
||||
SD3.uart = LPC_USART2;
|
||||
SD3.resources = &usart2_resources;
|
||||
#endif
|
||||
|
||||
#if LPC_SERIAL_USE_USART3
|
||||
sdObjectInit(&SD4, NULL, notify4);
|
||||
SD4.uart = LPC_USART3;
|
||||
SD4.resources = &usart3_resources;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -371,48 +417,11 @@ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
|
||||
config = &default_config;
|
||||
|
||||
if (sdp->state == SD_STOP) {
|
||||
#if LPC_SERIAL_USE_USART0
|
||||
if (&SD1 == sdp) {
|
||||
LPC_CCU1->CLK_M4_USART0_CFG.RUN = 1; /* Register interface branch clock. */
|
||||
LPC_CGU->BASE_UART0_CLK.PD = 0; /* Peripheral base clock. */
|
||||
LPC_CCU2->CLK_APB0_USART0_CFG.RUN = 1; /* Peripheral branch clock. */
|
||||
nvicEnableVector(USART0_IRQn,
|
||||
CORTEX_PRIORITY_MASK(LPC_SERIAL_USART0_IRQ_PRIORITY));
|
||||
}
|
||||
#endif
|
||||
#if LPC_SERIAL_USE_UART1
|
||||
if (&SD2 == sdp) {
|
||||
LPC_CCU1->CLK_M4_UART1_CFG.RUN = 1; /* Register interface branch clock. */
|
||||
LPC_CGU->BASE_UART1_CLK.PD = 0; /* Peripheral base clock. */
|
||||
LPC_CCU2->CLK_APB0_UART1_CFG.RUN = 1; /* Peripheral branch clock. */
|
||||
nvicEnableVector(UART1_IRQn,
|
||||
CORTEX_PRIORITY_MASK(LPC_SERIAL_UART1_IRQ_PRIORITY));
|
||||
}
|
||||
#endif
|
||||
#if LPC_SERIAL_USE_USART2
|
||||
if (&SD3 == sdp) {
|
||||
LPC_CCU1->CLK_M4_USART2_CFG.RUN = 1; /* Register interface branch clock. */
|
||||
LPC_CGU->BASE_UART2_CLK.PD = 0; /* Peripheral base clock. */
|
||||
LPC_CCU2->CLK_APB2_USART2_CFG.RUN = 1; /* Peripheral branch clock. */
|
||||
#if defined(LPC43XX_M4)
|
||||
nvicEnableVector(USART2_IRQn,
|
||||
CORTEX_PRIORITY_MASK(LPC_SERIAL_USART2_IRQ_PRIORITY));
|
||||
#endif
|
||||
#if defined(LPC43XX_M0)
|
||||
nvicEnableVector(USART2_OR_C_CAN1_IRQn,
|
||||
CORTEX_PRIORITY_MASK(LPC_SERIAL_USART2_IRQ_PRIORITY));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if LPC_SERIAL_USE_USART3
|
||||
if (&SD4 == sdp) {
|
||||
LPC_CCU1->CLK_M4_USART3_CFG.RUN = 1; /* Register interface branch clock. */
|
||||
LPC_CGU->BASE_UART3_CLK.PD = 0; /* Peripheral base clock. */
|
||||
LPC_CCU2->CLK_APB2_USART3_CFG.RUN = 1; /* Peripheral branch clock. */
|
||||
nvicEnableVector(USART3_IRQn,
|
||||
CORTEX_PRIORITY_MASK(LPC_SERIAL_USART3_IRQ_PRIORITY));
|
||||
}
|
||||
#endif
|
||||
base_clock_enable(&sdp->resources->base);
|
||||
branch_clock_enable(&sdp->resources->branch_register_if);
|
||||
branch_clock_enable(&sdp->resources->branch_peripheral);
|
||||
peripheral_reset(&sdp->resources->reset);
|
||||
interrupt_enable(&sdp->resources->interrupt);
|
||||
}
|
||||
uart_init(sdp, config);
|
||||
}
|
||||
@@ -429,56 +438,12 @@ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
|
||||
void sd_lld_stop(SerialDriver *sdp) {
|
||||
|
||||
if (sdp->state == SD_READY) {
|
||||
uart_deinit(sdp->uart);
|
||||
#if LPC_SERIAL_USE_USART0
|
||||
if (&SD1 == sdp) {
|
||||
LPC_CCU2->CLK_APB0_USART0_CFG.AUTO = 1; /* Peripheral branch clock. */
|
||||
LPC_CCU2->CLK_APB0_USART0_CFG.RUN = 0;
|
||||
LPC_CGU->BASE_UART0_CLK.PD = 1; /* Peripheral base clock. */
|
||||
LPC_CCU1->CLK_M4_USART0_CFG.AUTO = 1; /* Register interface branch clock. */
|
||||
LPC_CCU1->CLK_M4_USART0_CFG.RUN = 0;
|
||||
nvicDisableVector(USART0_IRQn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if LPC_SERIAL_USE_UART1
|
||||
if (&SD2 == sdp) {
|
||||
LPC_CCU2->CLK_APB0_UART1_CFG.AUTO = 1; /* Peripheral branch clock. */
|
||||
LPC_CCU2->CLK_APB0_UART0_CFG.RUN = 0;
|
||||
LPC_CGU->BASE_UART1_CLK.PD = 1; /* Peripheral base clock. */
|
||||
LPC_CCU1->CLK_M4_UART1_CFG.AUTO = 1; /* Register interface branch clock. */
|
||||
LPC_CCU1->CLK_M4_UART1_CFG.RUN = 0;
|
||||
nvicDisableVector(UART1_IRQn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if LPC_SERIAL_USE_USART2
|
||||
if (&SD3 == sdp) {
|
||||
LPC_CCU2->CLK_APB2_USART2_CFG.AUTO = 1; /* Peripheral branch clock. */
|
||||
LPC_CCU2->CLK_APB2_USART2_CFG.RUN = 0;
|
||||
LPC_CGU->BASE_UART2_CLK.PD = 1; /* Peripheral base clock. */
|
||||
LPC_CCU1->CLK_M4_USART2_CFG.AUTO = 1; /* Register interface branch clock. */
|
||||
LPC_CCU1->CLK_M4_USART2_CFG.RUN = 0;
|
||||
#if defined(LPC43XX_M4)
|
||||
nvicDisableVector(USART2_IRQn);
|
||||
#endif
|
||||
#if defined(LPC43XX_M0)
|
||||
nvicDisableVector(USART2_OR_C_CAN1_IRQn);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if LPC_SERIAL_USE_USART3
|
||||
if (&SD4 == sdp) {
|
||||
LPC_CCU2->CLK_APB2_USART3_CFG.AUTO = 1; /* Peripheral branch clock. */
|
||||
LPC_CCU2->CLK_APB2_USART3_CFG.RUN = 0;
|
||||
LPC_CGU->BASE_UART3_CLK.PD = 1; /* Peripheral base clock. */
|
||||
LPC_CCU1->CLK_M4_USART3_CFG.AUTO = 1; /* Register interface branch clock. */
|
||||
LPC_CCU1->CLK_M4_USART3_CFG.RUN = 0;
|
||||
nvicDisableVector(USART3_IRQn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
uart_deinit(&sdp->uart);
|
||||
interrupt_disable(&sdp->resources->interrupt);
|
||||
peripheral_reset(&sdp->resources->reset);
|
||||
branch_clock_disable(&sdp->resources->branch_peripheral);
|
||||
branch_clock_disable(&sdp->resources->branch_register_if);
|
||||
base_clock_disable(&sdp->resources->base);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -257,6 +257,17 @@
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Structure used for UART configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
base_clock_regs_t base;
|
||||
branch_clock_regs_t branch_register_if;
|
||||
branch_clock_regs_t branch_peripheral;
|
||||
peripheral_reset_t reset;
|
||||
interrupt_config_t interrupt;
|
||||
} uart_resources_t;
|
||||
|
||||
/**
|
||||
* @brief LPC Serial Driver configuration structure.
|
||||
* @details An instance of this structure must be passed to @p sdStart()
|
||||
@@ -294,7 +305,9 @@ typedef struct {
|
||||
uint8_t ob[SERIAL_BUFFERS_SIZE]; \
|
||||
/* End of the mandatory fields.*/ \
|
||||
/* Pointer to the UART registers block.*/ \
|
||||
LPC_USART_Type *uart;
|
||||
LPC_USART_Type *uart; \
|
||||
/* Pointer to the non-peripheral SSP resources.*/ \
|
||||
const ssp_resources_t * resources;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
|
@@ -48,6 +48,24 @@ SPIDriver SPID2;
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if LPC_SPI_USE_SSP0
|
||||
static const ssp_resources_t ssp0_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_SSP0_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1U << 6) },
|
||||
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_SSP0_CFG, .stat = &LPC_CCU1->CLK_M4_SSP0_STAT },
|
||||
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB0_SSP0_CFG, .stat = &LPC_CCU2->CLK_APB0_SSP0_STAT },
|
||||
.reset = { .output_index = 50 },
|
||||
};
|
||||
#endif /* LPC_SPI_USE_SSP0 */
|
||||
|
||||
#if LPC_SPI_USE_SSP1
|
||||
static const ssp_resources_t ssp1_resources = {
|
||||
.base = { .clk = &LPC_CGU->BASE_SSP1_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1U << 5) },
|
||||
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_SSP1_CFG, .stat = &LPC_CCU1->CLK_M4_SSP1_STAT },
|
||||
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB2_SSP1_CFG, .stat = &LPC_CCU2->CLK_APB2_SSP1_STAT },
|
||||
.reset = { .output_index = 51 },
|
||||
};
|
||||
#endif /* LPC_SPI_USE_SSP1 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
@@ -194,11 +212,13 @@ void spi_lld_init(void) {
|
||||
#if LPC_SPI_USE_SSP0
|
||||
spiObjectInit(&SPID1);
|
||||
SPID1.ssp = LPC_SSP0;
|
||||
SPID1.resources = &ssp0_resources;
|
||||
#endif /* LPC_SPI_USE_SSP0 */
|
||||
|
||||
#if LPC_SPI_USE_SSP1
|
||||
spiObjectInit(&SPID2);
|
||||
SPID2.ssp = LPC_SSP1;
|
||||
SPID2.resources = &ssp1_resources;
|
||||
#endif /* LPC_SPI_USE_SSP0 */
|
||||
}
|
||||
|
||||
@@ -212,11 +232,12 @@ void spi_lld_init(void) {
|
||||
void spi_lld_start(SPIDriver *spip) {
|
||||
|
||||
if (spip->state == SPI_STOP) {
|
||||
/* Clock activation.*/
|
||||
base_clock_enable(&spip->resources->base);
|
||||
branch_clock_enable(&spip->resources->branch_register_if);
|
||||
branch_clock_enable(&spip->resources->branch_peripheral);
|
||||
peripheral_reset(&spip->resources->reset);
|
||||
#if LPC_SPI_USE_SSP0
|
||||
if (&SPID1 == spip) {
|
||||
LPC_CCU1->CLK_M4_SSP0_CFG.RUN = 1;
|
||||
LPC_CGU->BASE_SSP0_CLK.PD = 0;
|
||||
#if defined(LPC43XX_M4)
|
||||
nvicEnableVector(SSP0_IRQn,
|
||||
CORTEX_PRIORITY_MASK(LPC_SPI_SSP0_IRQ_PRIORITY));
|
||||
@@ -229,8 +250,6 @@ void spi_lld_start(SPIDriver *spip) {
|
||||
#endif
|
||||
#if LPC_SPI_USE_SSP1
|
||||
if (&SPID2 == spip) {
|
||||
LPC_CCU1->CLK_M4_SSP1_CFG.RUN = 1;
|
||||
LPC_CGU->BASE_SSP1_CLK.PD = 0;
|
||||
#if defined(LPC43XX_M4)
|
||||
nvicEnableVector(SSP1_IRQn,
|
||||
CORTEX_PRIORITY_MASK(LPC_SPI_SSP1_IRQ_PRIORITY));
|
||||
@@ -267,18 +286,44 @@ void spi_lld_stop(SPIDriver *spip) {
|
||||
spip->ssp->IMSC = 0;
|
||||
#if LPC_SPI_USE_SSP0
|
||||
if (&SPID1 == spip) {
|
||||
LPC_CGU->BASE_SSP0_CLK.PD = 1;
|
||||
LPC_CCU1->CLK_M4_SSP0_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_M4_SSP0_CFG.RUN = 0;
|
||||
#if defined(LPC43XX_M4)
|
||||
nvicDisableVector(SSP0_IRQn);
|
||||
#endif
|
||||
#if defined(LPC43XX_M0)
|
||||
#if LPC_SPI_USE_SSP1
|
||||
/* Disable only if other SSP is stopped. */
|
||||
/* TODO: Won't work correctly if SSPs are split between cores! */
|
||||
if(SPID2.state == SPI_STOP) {
|
||||
#endif
|
||||
nvicDisableVector(SSP0_OR_SSP1_IRQn);
|
||||
#if LPC_SPI_USE_SSP1
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if LPC_SPI_USE_SSP1
|
||||
if (&SPID2 == spip) {
|
||||
LPC_CGU->BASE_SSP1_CLK.PD = 1;
|
||||
LPC_CCU1->CLK_M4_SSP1_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_M4_SSP1_CFG.RUN = 0;
|
||||
#if defined(LPC43XX_M4)
|
||||
nvicDisableVector(SSP1_IRQn);
|
||||
#endif
|
||||
#if defined(LPC43XX_M0)
|
||||
#if LPC_SPI_USE_SSP0
|
||||
/* Disable only if other SSP is stopped. */
|
||||
/* TODO: Won't work correctly if SSPs are split between cores! */
|
||||
if(SPID1.state == SPI_STOP) {
|
||||
#endif
|
||||
nvicDisableVector(SSP0_OR_SSP1_IRQn);
|
||||
#if LPC_SPI_USE_SSP1
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
peripheral_reset(&spip->resources->reset);
|
||||
branch_clock_disable(&spip->resources->branch_peripheral);
|
||||
branch_clock_disable(&spip->resources->branch_register_if);
|
||||
base_clock_disable(&spip->resources->base);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -220,6 +220,16 @@
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Structure used for SSP configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
base_clock_regs_t base;
|
||||
branch_clock_regs_t branch_register_if;
|
||||
branch_clock_regs_t branch_peripheral;
|
||||
peripheral_reset_t reset;
|
||||
} ssp_resources_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an SPI driver.
|
||||
*/
|
||||
@@ -296,6 +306,10 @@ struct SPIDriver {
|
||||
* @brief Pointer to the SSP registers block.
|
||||
*/
|
||||
LPC_SSPx_Type *ssp;
|
||||
/**
|
||||
* @brief Pointer to the non-peripheral SSP resources.
|
||||
*/
|
||||
const ssp_resources_t * resources;
|
||||
/**
|
||||
* @brief Number of bytes yet to be received.
|
||||
*/
|
||||
|
@@ -100,6 +100,9 @@ void systick_stop() {
|
||||
*/
|
||||
void hal_lld_init(void) {
|
||||
/* Initialize timer 3 to serve as a cycle (PCLK) counter. */
|
||||
LPC_CCU1->CLK_M4_TIMER3_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_M4_TIMER3_CFG.RUN = 1;
|
||||
while(!LPC_CCU1->CLK_M4_TIMER3_STAT.RUN);
|
||||
LPC_TIMER3->TCR = (1 << 1); /* CRST=1 */
|
||||
LPC_TIMER3->TCR = 0; /* CRST=0 */
|
||||
LPC_TIMER3->TC = 0;
|
||||
@@ -109,6 +112,9 @@ void hal_lld_init(void) {
|
||||
/* Initialize repetitive interrupt timer (RIT) to act like SysTick for
|
||||
* operating system process timing.
|
||||
*/
|
||||
LPC_CCU1->CLK_M4_RITIMER_CFG.AUTO = 1;
|
||||
LPC_CCU1->CLK_M4_RITIMER_CFG.RUN = 1;
|
||||
while(!LPC_CCU1->CLK_M4_RITIMER_STAT.RUN);
|
||||
LPC_RITIMER->CTRL =
|
||||
(1 << 0) /* RITINT */
|
||||
| (1 << 1) /* RITENCLR */
|
||||
|
@@ -101,6 +101,7 @@ typedef enum IRQn {
|
||||
|
||||
#include "core_cm0.h" /* Cortex-M0 processor and core peripherals */
|
||||
#include "lpc43xx.inc"
|
||||
#include "lpc43xx.h"
|
||||
|
||||
#endif /* __LPC43XX_M0_H */
|
||||
|
||||
|
@@ -8,6 +8,7 @@ set(PLATFORMSRC
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/sdc_lld.c
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/serial_lld.c
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/lpc43xx.c
|
||||
)
|
||||
|
||||
# Required include directories
|
||||
|
@@ -6,7 +6,8 @@ PLATFORMSRC = ${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M0/hal_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/rtc_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/sdc_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/serial_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/lpc43xx.c
|
||||
|
||||
# Required include directories
|
||||
PLATFORMINC = ${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M0 \
|
||||
|
@@ -122,6 +122,7 @@ typedef enum IRQn {
|
||||
|
||||
#include "core_cm4.h" /* Cortex-M4 processor and core peripherals */
|
||||
#include "lpc43xx.inc"
|
||||
#include "lpc43xx.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
@@ -8,6 +8,7 @@ set(PLATFORMSRC
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/sdc_lld.c
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/serial_lld.c
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/lpc43xx.c
|
||||
)
|
||||
|
||||
# Required include directories
|
||||
|
@@ -6,7 +6,8 @@ PLATFORMSRC = ${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M4/hal_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/rtc_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/sdc_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/serial_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c \
|
||||
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/lpc43xx.c
|
||||
|
||||
# Required include directories
|
||||
PLATFORMINC = ${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M4 \
|
||||
|
@@ -29,22 +29,32 @@
|
||||
namespace cpld {
|
||||
namespace max5 {
|
||||
|
||||
/* Enter ISP:
|
||||
* Ensures that the I/O pins transition smoothly from user mode to ISP
|
||||
* mode.
|
||||
*/
|
||||
void CPLD::enter_isp() {
|
||||
/* Enter ISP */
|
||||
shift_ir(0x2cc); //(199);
|
||||
void CPLD::bypass() {
|
||||
shift_ir(instruction_t::BYPASS);
|
||||
jtag.runtest_tck(18003);
|
||||
}
|
||||
|
||||
void CPLD::sample() {
|
||||
shift_ir(instruction_t::SAMPLE);
|
||||
jtag.runtest_tck(93);
|
||||
for(size_t i=0; i<80; i++) {
|
||||
jtag.shift_dr(3, 0b111);
|
||||
}
|
||||
}
|
||||
|
||||
void CPLD::clamp() {
|
||||
shift_ir(instruction_t::CLAMP);
|
||||
jtag.runtest_tck(93);
|
||||
}
|
||||
|
||||
void CPLD::enable() {
|
||||
shift_ir(instruction_t::ISC_ENABLE);
|
||||
jtag.runtest_tck(18003); // 1ms
|
||||
}
|
||||
|
||||
void CPLD::exit_isp() {
|
||||
/* Exit ISP? Reset? */
|
||||
shift_ir(0x201); //166);
|
||||
void CPLD::disable() {
|
||||
shift_ir(instruction_t::ISC_DISABLE);
|
||||
jtag.runtest_tck(18003); // 1ms
|
||||
shift_ir(0x3FF);
|
||||
jtag.runtest_tck(18000); // 1ms
|
||||
}
|
||||
|
||||
/* Sector erase:
|
||||
@@ -86,7 +96,7 @@ bool CPLD::program(
|
||||
* one bit changing, a write must be a multiple of a particular
|
||||
* length (64 bits)? */
|
||||
sector_select(0x0000);
|
||||
shift_ir(0x2F4); // Program
|
||||
shift_ir(instruction_t::ISC_PROGRAM);
|
||||
jtag.runtest_tck(93); // 5 us
|
||||
|
||||
/* TODO: Use data from cpld_block_0, with appropriate bit(s) changed */
|
||||
@@ -122,20 +132,20 @@ uint32_t CPLD::crc() {
|
||||
}
|
||||
|
||||
void CPLD::sector_select(const uint16_t id) {
|
||||
shift_ir(0x203); // Sector select
|
||||
shift_ir(instruction_t::ISC_ADDRESS_SHIFT);
|
||||
jtag.runtest_tck(93); // 5us
|
||||
jtag.shift_dr(13, id); // Sector ID
|
||||
}
|
||||
|
||||
bool CPLD::idcode_ok() {
|
||||
shift_ir(Instruction::IDCODE);
|
||||
const auto idcode = jtag.shift_dr(32, 0);
|
||||
return (idcode == IDCODE);
|
||||
shift_ir(instruction_t::IDCODE);
|
||||
const auto idcode_read = jtag.shift_dr(idcode_length, 0);
|
||||
return (idcode_read == idcode);
|
||||
}
|
||||
|
||||
std::array<uint16_t, 5> CPLD::read_silicon_id() {
|
||||
sector_select(0x0089);
|
||||
shift_ir(0x205);
|
||||
shift_ir(instruction_t::ISC_READ);
|
||||
jtag.runtest_tck(93); // 5us
|
||||
|
||||
std::array<uint16_t, 5> silicon_id;
|
||||
@@ -164,9 +174,15 @@ bool CPLD::silicon_id_ok() {
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t CPLD::usercode() {
|
||||
shift_ir(instruction_t::USERCODE);
|
||||
jtag.runtest_tck(93); // 5us
|
||||
return jtag.shift_dr(32, 0xffffffff);
|
||||
}
|
||||
|
||||
void CPLD::erase_sector(const uint16_t id) {
|
||||
sector_select(id);
|
||||
shift_ir(0x2F2); // Erase pulse
|
||||
shift_ir(instruction_t::ISC_ERASE);
|
||||
jtag.runtest_tck(9000003); // 500ms
|
||||
}
|
||||
|
||||
@@ -176,7 +192,7 @@ void CPLD::program_block(
|
||||
const size_t count
|
||||
) {
|
||||
sector_select(id);
|
||||
shift_ir(0x2F4); // Program
|
||||
shift_ir(instruction_t::ISC_PROGRAM);
|
||||
jtag.runtest_tck(93); // 5us
|
||||
|
||||
for(size_t i=0; i<count; i++) {
|
||||
@@ -191,19 +207,19 @@ bool CPLD::verify_block(
|
||||
const size_t count
|
||||
) {
|
||||
sector_select(id);
|
||||
shift_ir(0x205); // Read
|
||||
shift_ir(instruction_t::ISC_READ);
|
||||
jtag.runtest_tck(93); // 5us
|
||||
|
||||
bool success = true;
|
||||
for(size_t i=0; i<count; i++) {
|
||||
const auto from_device = jtag.shift_dr(16, 0xffff);
|
||||
if( (id == 0) && (i == 0) ) {
|
||||
// Account for bit that indicates bitstream is valid.
|
||||
if( (from_device & 0xfbff) != (data[i] & 0xfbff) ) {
|
||||
success = false;
|
||||
}
|
||||
} else {
|
||||
if( from_device != data[i] ) {
|
||||
if( from_device != data[i] ) {
|
||||
if( (id == 0) && (i == 0) ) {
|
||||
// Account for bit that indicates bitstream is valid.
|
||||
if( (from_device & 0xfbff) != (data[i] & 0xfbff) ) {
|
||||
success = false;
|
||||
}
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
@@ -213,7 +229,7 @@ bool CPLD::verify_block(
|
||||
|
||||
bool CPLD::is_blank_block(const uint16_t id, const size_t count) {
|
||||
sector_select(id);
|
||||
shift_ir(0x205); // Read
|
||||
shift_ir(instruction_t::ISC_READ);
|
||||
jtag.runtest_tck(93); // 5us
|
||||
|
||||
bool success = true;
|
||||
@@ -228,7 +244,7 @@ bool CPLD::is_blank_block(const uint16_t id, const size_t count) {
|
||||
|
||||
void CPLD::block_crc(const uint16_t id, const size_t count, crc_t& crc) {
|
||||
sector_select(id);
|
||||
shift_ir(0x205); // Read
|
||||
shift_ir(instruction_t::ISC_READ);
|
||||
jtag.runtest_tck(93); // 5us
|
||||
|
||||
for(size_t i=0; i<count; i++) {
|
||||
|
@@ -46,6 +46,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void bypass();
|
||||
void sample();
|
||||
void clamp();
|
||||
|
||||
void reset() {
|
||||
jtag.reset();
|
||||
}
|
||||
@@ -56,7 +60,7 @@ public:
|
||||
|
||||
bool idcode_ok();
|
||||
|
||||
void enter_isp();
|
||||
void enable();
|
||||
|
||||
/* Check ID:
|
||||
* The silicon ID is checked before any Program or Verify process. The
|
||||
@@ -65,7 +69,9 @@ public:
|
||||
*/
|
||||
bool silicon_id_ok();
|
||||
|
||||
void exit_isp(); // I think that's what the code does...
|
||||
uint32_t usercode();
|
||||
|
||||
void disable();
|
||||
|
||||
void bulk_erase();
|
||||
|
||||
@@ -85,18 +91,39 @@ public:
|
||||
|
||||
std::pair<bool, uint8_t> boundary_scan();
|
||||
|
||||
enum class Instruction {
|
||||
BYPASS = 0b1111111111,
|
||||
EXTEST = 0b0000001111,
|
||||
SAMPLE = 0b0000000101,
|
||||
IDCODE = 0b0000000110,
|
||||
USERCODE = 0b0000000111,
|
||||
CLAMP = 0b0000001010,
|
||||
HIGHZ = 0b0000001011
|
||||
};
|
||||
private:
|
||||
using idcode_t = uint32_t;
|
||||
static constexpr size_t idcode_length = 32;
|
||||
static constexpr idcode_t idcode = 0b00000010000010100101000011011101;
|
||||
static constexpr idcode_t idcode_mask = 0b11111111111111111111111111111111;
|
||||
|
||||
static constexpr size_t ir_length = 10;
|
||||
|
||||
void shift_ir(const Instruction instruction) {
|
||||
shift_ir(static_cast<uint32_t>(instruction));
|
||||
using ir_t = uint16_t;
|
||||
|
||||
enum class instruction_t : ir_t {
|
||||
BYPASS = 0b1111111111, // 0x3ff
|
||||
EXTEST = 0b0000001111, // 0x00f
|
||||
SAMPLE = 0b0000000101, // 0x005
|
||||
IDCODE = 0b0000000110, // 0x006
|
||||
USERCODE = 0b0000000111, // 0x007
|
||||
CLAMP = 0b0000001010, // 0x00a
|
||||
HIGHZ = 0b0000001011, // 0x00b
|
||||
ISC_ENABLE = 0b1011001100, // 0x2cc
|
||||
ISC_DISABLE = 0b1000000001, // 0x201
|
||||
ISC_PROGRAM = 0b1011110100, // 0x2f4
|
||||
ISC_ERASE = 0b1011110010, // 0x2f2
|
||||
ISC_ADDRESS_SHIFT = 0b1000000011, // 0x203
|
||||
ISC_READ = 0b1000000101, // 0x205
|
||||
ISC_NOOP = 0b1000010000, // 0x210
|
||||
};
|
||||
|
||||
void shift_ir(const instruction_t instruction) {
|
||||
shift_ir(static_cast<ir_t>(instruction));
|
||||
}
|
||||
|
||||
void shift_ir(const uint32_t value) {
|
||||
jtag.shift_ir(ir_length, value);
|
||||
}
|
||||
|
||||
void shift_dr(std::bitset<240>& value) {
|
||||
@@ -105,7 +132,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t shift_dr(const size_t count, const uint32_t value) {
|
||||
return jtag.shift_dr(count, value);
|
||||
}
|
||||
|
||||
jtag::JTAG& jtag;
|
||||
|
||||
std::array<uint16_t, 5> read_silicon_id();
|
||||
@@ -146,18 +176,6 @@ private:
|
||||
|
||||
using crc_t = CRC<32, true, true>;
|
||||
void block_crc(const uint16_t id, const size_t count, crc_t& crc);
|
||||
|
||||
const uint32_t IDCODE = 0b00000010000010100101000011011101;
|
||||
|
||||
const size_t IR_LENGTH = 10;
|
||||
|
||||
void shift_ir(const uint32_t value) {
|
||||
jtag.shift_ir(IR_LENGTH, value);
|
||||
}
|
||||
|
||||
uint32_t shift_dr(const size_t count, const uint32_t value) {
|
||||
return jtag.shift_dr(count, value);
|
||||
}
|
||||
};
|
||||
/*
|
||||
class ModeISP {
|
||||
|
@@ -54,11 +54,9 @@ bool update_if_necessary(
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Enter ISP:
|
||||
* Ensures that the I/O pins transition smoothly from user mode to ISP
|
||||
* mode. All pins are tri-stated.
|
||||
*/
|
||||
cpld.enter_isp();
|
||||
cpld.sample();
|
||||
cpld.bypass();
|
||||
cpld.enable();
|
||||
|
||||
/* If silicon ID doesn't match, there's a serious problem. Leave CPLD
|
||||
* in passive state.
|
||||
@@ -79,7 +77,13 @@ bool update_if_necessary(
|
||||
* passive (ISP) state.
|
||||
*/
|
||||
if( ok ) {
|
||||
cpld.exit_isp();
|
||||
cpld.disable();
|
||||
cpld.bypass();
|
||||
|
||||
/* Initiate SRAM reload from flash we just programmed. */
|
||||
cpld.sample();
|
||||
cpld.clamp();
|
||||
cpld.disable();
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
@@ -64,18 +64,6 @@ static void runtime_error() {
|
||||
|
||||
extern "C" {
|
||||
|
||||
void __early_init(void) {
|
||||
/* Enable unaligned exception handler */
|
||||
SCB_CCR |= (1 << 3);
|
||||
|
||||
#if defined(LPC43XX_M4)
|
||||
/* Enable MemManage, BusFault, UsageFault exception handlers */
|
||||
SCB_SHCSR |= (1 << 16);
|
||||
SCB_SHCSR |= (1 << 17);
|
||||
SCB_SHCSR |= (1 << 18);
|
||||
#endif
|
||||
}
|
||||
|
||||
void port_halt(void) {
|
||||
// Copy debug panic message to M0 region.
|
||||
const auto* p = dbg_panic_msg;
|
||||
|
@@ -176,6 +176,18 @@ struct PinConfig {
|
||||
static constexpr PinConfig i2c(const uint32_t mode) {
|
||||
return { .mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 1, .ifilt = 1 };
|
||||
}
|
||||
|
||||
static constexpr PinConfig spifi_sck(const uint32_t mode ) {
|
||||
return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
|
||||
}
|
||||
|
||||
static constexpr PinConfig spifi_inout(const uint32_t mode) {
|
||||
return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
|
||||
}
|
||||
|
||||
static constexpr PinConfig spifi_cs(const uint32_t mode) {
|
||||
return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 0, .ifilt = 0 };
|
||||
}
|
||||
};
|
||||
|
||||
struct Pin {
|
||||
@@ -207,7 +219,7 @@ struct Pin {
|
||||
|
||||
void mode(const uint_fast16_t mode) const {
|
||||
LPC_SCU->SFSP[_pin_port][_pin_pad] =
|
||||
(LPC_SCU->SFSP[_pin_port][_pin_pad] & ~(7U << 0)) | mode;
|
||||
(LPC_SCU->SFSP[_pin_port][_pin_pad] & 0xfffffff8) | mode;
|
||||
}
|
||||
|
||||
void configure(const PinConfig config) const {
|
||||
|
@@ -71,8 +71,7 @@ void reset() {
|
||||
/*| rgu::Reset::SPIFI*/
|
||||
| rgu::Reset::CAN1
|
||||
| rgu::Reset::CAN0
|
||||
/* Don't reset M0 if that's the core we're running on! */
|
||||
/*| rgu::Reset::M0APP */
|
||||
| rgu::Reset::M0APP
|
||||
| rgu::Reset::SGPIO
|
||||
| rgu::Reset::SPI
|
||||
);
|
||||
|
@@ -32,16 +32,6 @@ struct I2CClockConfig {
|
||||
float bus_f;
|
||||
float high_period_ns;
|
||||
|
||||
constexpr I2CClockConfig(
|
||||
float clock_source_f,
|
||||
float bus_f,
|
||||
float high_period_ns
|
||||
) : clock_source_f(clock_source_f),
|
||||
bus_f(bus_f),
|
||||
high_period_ns(high_period_ns)
|
||||
{
|
||||
}
|
||||
|
||||
static constexpr float period_ns(const float f) {
|
||||
return 1e9 / f;
|
||||
}
|
||||
|
@@ -356,7 +356,7 @@ enum class Status {
|
||||
};
|
||||
|
||||
inline void reset(const Reset reset) {
|
||||
LPC_RGU->RESET_CTRL[toUType(reset) >> 5] |= (1U << (toUType(reset) & 0x1f));
|
||||
LPC_RGU->RESET_CTRL[toUType(reset) >> 5] = (1U << (toUType(reset) & 0x1f));
|
||||
}
|
||||
|
||||
inline void reset_mask(const uint64_t mask) {
|
||||
|
@@ -30,7 +30,7 @@ enum Pins {
|
||||
P0_0, P0_1,
|
||||
P1_0, P1_1, P1_2, P1_3, P1_4, P1_5, P1_6, P1_7, P1_8, P1_9, P1_10, P1_11, P1_12, P1_13, P1_14, P1_15, P1_16, P1_17, P1_18, P1_19, P1_20,
|
||||
P2_0, P2_1, P2_2, P2_3, P2_4, P2_5, P2_6, P2_7, P2_8, P2_9, P2_10, P2_11, P2_12, P2_13,
|
||||
P3_0, P3_1, P3_2, /*P3_3, P3_4, P3_5, P3_6, P3_7, P3_8,*/
|
||||
P3_0, P3_1, P3_2,
|
||||
P4_0, P4_1, P4_2, P4_3, P4_4, P4_5, P4_6, P4_7, P4_8, P4_9, P4_10,
|
||||
P5_0, P5_1, P5_2, P5_3, P5_4, P5_5, P5_6, P5_7,
|
||||
P6_0, P6_1, P6_2, P6_3, P6_4, P6_5, P6_6, P6_7, P6_8, P6_9, P6_10, P6_11, P6_12,
|
||||
@@ -44,13 +44,13 @@ constexpr Pin pins[] = {
|
||||
[P0_0] = { 0, 0, PinConfig::sgpio_inout_fast(3) }, /* SGPIO0/P75/BANK2F3M3: CPLD.89/HOST_DATA0(IO) */
|
||||
[P0_1] = { 0, 1, PinConfig::sgpio_inout_fast(3) }, /* SGPIO1/BANK2F3M5: CPLD.79/HOST_DATA1(IO) */
|
||||
[P1_0] = { 1, 0, PinConfig::sgpio_inout_fast(6) }, /* SGPIO7/P76/BANK2F3M7: CPLD.77/HOST_DATA7(IO) */
|
||||
[P1_1] = { 1, 1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* P1_1/P74: 10K PU, BOOT0 */
|
||||
[P1_2] = { 1, 2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* P1_2/P73: 10K PD, BOOT1 */
|
||||
[P1_1] = { 1, 1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P1_1/P74: 10K PU, BOOT0 */
|
||||
[P1_2] = { 1, 2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P1_2/P73: 10K PD, BOOT1 */
|
||||
[P1_3] = { 1, 3, { .mode=5, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* SSP1_MISO/P41: MAX2837.DOUT(O) */
|
||||
[P1_4] = { 1, 4, { .mode=5, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* SSP1_MOSI/P40: MAX2837.DIN(I), MAX5864.DIN(I) */
|
||||
[P1_5] = { 1, 5, { .mode=0, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* SD_POW: PortaPack CPLD.TDO(O) */
|
||||
[P1_6] = { 1, 6, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_CMD: PortaPack SD.CMD(IO) */
|
||||
[P1_7] = { 1, 7, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !MIX_BYPASS/P35: U1.VCTL1(I), U11.VCTL2(I), U9.V2(I) */
|
||||
[P1_7] = { 1, 7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !MIX_BYPASS/P35: U1.VCTL1(I), U11.VCTL2(I), U9.V2(I) */
|
||||
[P1_8] = { 1, 8, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* SD_VOLT0: PortaPack CPLD.TMS(I) */
|
||||
[P1_9] = { 1, 9, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT0: PortaPack SD.DAT0(IO) */
|
||||
[P1_10] = { 1, 10, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT1: PortaPack SD.DAT1(IO) */
|
||||
@@ -62,8 +62,8 @@ constexpr Pin pins[] = {
|
||||
[P1_16] = { 1, 16, PinConfig::sgpio_inout_fast(2) }, /* SGPIO3/BANK2F3M10: CPLD.72/HOST_DATA3(IO) */
|
||||
[P1_17] = { 1, 17, PinConfig::sgpio_out_fast_with_pullup(6) }, /* SGPIO11/P79/BANK2F3M11: CPLD.71/HOST_DIRECTION(I) */
|
||||
[P1_18] = { 1, 18, PinConfig::gpio_out_with_pulldown(0) }, /* SGPIO12/BANK2F3M12: CPLD.70/HOST_INVERT(I) */
|
||||
[P1_19] = { 1, 19, { .mode=1, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* SSP1_SCK/P39: MAX2837.SCLK(I), MAX5864.SCLK(I) */
|
||||
[P1_20] = { 1, 20, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* CS_XCVR/P53: MAX2837.CS(I) */
|
||||
[P1_19] = { 1, 19, { .mode=1, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* SSP1_SCK/P39: MAX2837.SCLK(I), MAX5864.SCLK(I) */
|
||||
[P1_20] = { 1, 20, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CS_XCVR/P53: MAX2837.CS(I) */
|
||||
[P2_0] = { 2, 0, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* U0_TXD: PortaPack P2_0/IO_STBX */
|
||||
[P2_1] = { 2, 1, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* U0_RXD: PortaPack P2_1/ADDR */
|
||||
[P2_2] = { 2, 2, PinConfig::sgpio_inout_fast(0) }, /* SGPIO6/BANK2F3M16: CPLD.61/HOST_DATA6(IO) */
|
||||
@@ -71,53 +71,47 @@ constexpr Pin pins[] = {
|
||||
[P2_4] = { 2, 4, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* I2C1_SCL: PortaPack P2_4/LCD_RDX */
|
||||
[P2_5] = { 2, 5, { .mode=4, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* RX/P43: U7.VCTL1(I), U10.VCTL1(I), U2.VCTL1(I) */
|
||||
[P2_6] = { 2, 6, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIXER_SCLK/P31: 33pF, RFFC5072.SCLK(I) */
|
||||
[P2_7] = { 2, 7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* ISP: 10K PU, Unused */
|
||||
[P2_7] = { 2, 7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* ISP: 10K PU, Unused */
|
||||
[P2_8] = { 2, 8, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P2_8: 10K PD, BOOT2, DFU switch, PortaPack P2_8/<unused> */
|
||||
[P2_9] = { 2, 9, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* P2_9: 10K PD, BOOT3, PortaPack P2_9/LCD_WRX */
|
||||
[P2_10] = { 2, 10, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* AMP_BYPASS/P50: U14.V2(I), U12.V2(I) */
|
||||
[P2_11] = { 2, 11, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RX_AMP/P49: U12.V1(I), U14.V3(I) */
|
||||
[P2_10] = { 2, 10, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* AMP_BYPASS/P50: U14.V2(I), U12.V2(I) */
|
||||
[P2_11] = { 2, 11, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RX_AMP/P49: U12.V1(I), U14.V3(I) */
|
||||
[P2_12] = { 2, 12, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !RX_AMP_PWR/P52: 10K PU, Q1.G(I), power to U13 (RX amp) */
|
||||
[P2_13] = { 2, 13, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* P2_13: PortaPack P2_13/DIR */
|
||||
[P3_0] = { 3, 0, { .mode=2, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* I2S0_TX_SCK: PortaPack I2S0_TX_SCK(I) */
|
||||
[P3_1] = { 3, 1, { .mode=0, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* I2S0_RX_WS: PortaPack I2S0_TX_WS(I). Input enabled to fold back into RX. */
|
||||
[P3_2] = { 3, 2, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_SDA: PortaPack I2S0_TX_SDA(I) */
|
||||
//[P3_3] = { 3, 3, { .mode=3, .pd=1, .pu=0, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_SCK: W25Q80BV.CLK(I), enable input buffer for timing feedback */
|
||||
//[P3_4] = { 3, 4, { .mode=3, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_SIO3/P82: W25Q80BV.HOLD(IO) */
|
||||
//[P3_5] = { 3, 5, { .mode=3, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_SIO2/P81: W25Q80BV.WP(IO) */
|
||||
//[P3_6] = { 3, 6, { .mode=3, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_MISO: W25Q80BV.DO(IO) */
|
||||
//[P3_7] = { 3, 7, { .mode=3, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_MOSI: W25Q80BV.DI(IO) */
|
||||
//[P3_8] = { 3, 8, { .mode=3, .pd=0, .pu=1, .fast=1, .input=0, .ifilt=1 } }, /* SPIFI_CS/P68: W25Q80BV.CS(I) */
|
||||
[P4_0] = { 4, 0, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* HP/P44: U6.VCTL1(I), U5.VCTL2(I) */
|
||||
[P4_0] = { 4, 0, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* HP/P44: U6.VCTL1(I), U5.VCTL2(I) */
|
||||
[P4_1] = { 4, 1, PinConfig::gpio_led(0) }, /* LED1: LED1.A(I) */
|
||||
[P4_2] = { 4, 2, PinConfig::gpio_led(0) }, /* LED2: LED2.A(I) */
|
||||
[P4_3] = { 4, 3, PinConfig::sgpio_in_fast(7) }, /* SGPIO9/P77/BANK2F3M1: CPLD.91/HOST_CAPTURE(O) */
|
||||
[P4_4] = { 4, 4, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TXENABLE/P55: MAX2837.TXENABLE(I) */
|
||||
[P4_5] = { 4, 5, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RXENABLE/P56: MAX2837.RXENABLE(I) */
|
||||
[P4_4] = { 4, 4, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TXENABLE/P55: MAX2837.TXENABLE(I) */
|
||||
[P4_5] = { 4, 5, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RXENABLE/P56: MAX2837.RXENABLE(I) */
|
||||
[P4_6] = { 4, 6, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* XCVR_EN: 10K PD, MAX2837.ENABLE(I) */
|
||||
[P4_7] = { 4, 7, { .mode=1, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=0 } }, /* GP_CLKIN/P72/MCU_CLK: SI5351C.CLK7(O) */
|
||||
[P4_8] = { 4, 8, PinConfig::gpio_out_with_pullup(4) }, /* SGPIO13/BANK2F3M2: CPLD.90/HOST_DECIM_SEL0(I) */
|
||||
[P4_9] = { 4, 9, PinConfig::gpio_out_with_pullup(4) }, /* SGPIO14/BANK2F3M4: CPLD.81/HOST_DECIM_SEL1(I) */
|
||||
[P4_10] = { 4, 10, PinConfig::gpio_out_with_pullup(4) }, /* SGPIO15/BANK2F3M6: CPLD.78/HOST_DECIM_SEL2(I) */
|
||||
[P5_0] = { 5, 0, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !VAA_ENABLE: 10K PU, Q3.G(I), power to VAA */
|
||||
[P5_1] = { 5, 1, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* LP/P45: U6.VCTL2(I), U5.VCTL1(I) */
|
||||
[P5_2] = { 5, 2, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX_MIX_BP/P46: U9.V1(I) */
|
||||
[P5_3] = { 5, 3, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* RX_MIX_BP/P47: U9.V3(I) */
|
||||
[P5_1] = { 5, 1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* LP/P45: U6.VCTL2(I), U5.VCTL1(I) */
|
||||
[P5_2] = { 5, 2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX_MIX_BP/P46: U9.V1(I) */
|
||||
[P5_3] = { 5, 3, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RX_MIX_BP/P47: U9.V3(I) */
|
||||
[P5_4] = { 5, 4, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIXER_ENX/P32: 10K PU, 33pF, RFFC5072.ENX(I) */
|
||||
[P5_5] = { 5, 5, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIXER_RESETX/P33: 10K PU, 33pF, RFFC5072.RESETX(I) */
|
||||
[P5_6] = { 5, 6, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX_AMP/P48: U12.V3(I), U14.V1(I) */
|
||||
[P5_7] = { 5, 7, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* CS_AD/P54: MAX5864.CS(I) */
|
||||
[P5_6] = { 5, 6, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX_AMP/P48: U12.V3(I), U14.V1(I) */
|
||||
[P5_7] = { 5, 7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CS_AD/P54: MAX5864.CS(I) */
|
||||
[P6_0] = { 6, 0, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_MCLK: Unused */
|
||||
[P6_1] = { 6, 1, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CPLD_TCK: CPLD.TCK(I), PortaPack CPLD.TCK(I) */
|
||||
[P6_2] = { 6, 2, { .mode=0, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* CPLD_TDI: CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) */
|
||||
[P6_1] = { 6, 1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CPLD_TCK: CPLD.TCK(I), PortaPack CPLD.TCK(I) */
|
||||
[P6_2] = { 6, 2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* CPLD_TDI: CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) */
|
||||
[P6_3] = { 6, 3, PinConfig::sgpio_inout_fast(2) }, /* SGPIO4/BANK2F3M14: CPLD.67/HOST_DATA4(IO) */
|
||||
[P6_4] = { 6, 4, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* MIXER_SDATA/P27: 33pF, RFFC5072.SDATA(IO) */
|
||||
[P6_5] = { 6, 5, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* CPLD_TMS: CPLD.TMS(I) */
|
||||
[P6_5] = { 6, 5, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CPLD_TMS: CPLD.TMS(I) */
|
||||
[P6_6] = { 6, 6, PinConfig::sgpio_inout_fast(2) }, /* SGPIO5/BANK2F3M15: CPLD.64/HOST_DATA5(IO) */
|
||||
[P6_7] = { 6, 7, { .mode=4, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX/P42: U7.VCTL2(I), U10.VCTL2(I), U2.VCTL2(I) */
|
||||
[P6_8] = { 6, 8, { .mode=4, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* MIX_BYPASS/P34: U1.VCTL2(I), U11.VCTL1(I) */
|
||||
[P6_7] = { 6, 7, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX/P42: U7.VCTL2(I), U10.VCTL2(I), U2.VCTL2(I) */
|
||||
[P6_8] = { 6, 8, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIX_BYPASS/P34: U1.VCTL2(I), U11.VCTL1(I) */
|
||||
[P6_9] = { 6, 9, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !TX_AMP_PWR/P51: 10K PU, Q2.G(I), power to U25 (TX amp) */
|
||||
[P6_10] = { 6, 10, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* EN1V8/P70: 10K PD, TPS62410.EN2(I), 1V8LED.A(I) */
|
||||
[P6_11] = { 6, 11, { .mode=0, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* VREGMODE/P69: TPS62410.MODE/DATA(I) */
|
||||
[P6_11] = { 6, 11, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* VREGMODE/P69: TPS62410.MODE/DATA(I) */
|
||||
[P6_12] = { 6, 12, PinConfig::gpio_led(0) }, /* LED3: LED3.A(I) */
|
||||
[P7_0] = { 7, 0, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_8: PortaPack GPIO3_8(IO) */
|
||||
[P7_1] = { 7, 1, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_9: PortaPack GPIO3_9(IO) */
|
||||
@@ -127,7 +121,7 @@ constexpr Pin pins[] = {
|
||||
[P7_5] = { 7, 5, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_13: PortaPack GPIO3_13(IO) */
|
||||
[P7_6] = { 7, 6, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_14: PortaPack GPIO3_14(IO) */
|
||||
[P7_7] = { 7, 7, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_15: PortaPack GPIO3_15(IO) */
|
||||
[P9_5] = { 9, 5, { .mode=3, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* CPLD_TDO: CPLD.TDO(O) */
|
||||
[P9_5] = { 9, 5, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* CPLD_TDO: CPLD.TDO(O) */
|
||||
[P9_6] = { 9, 6, PinConfig::sgpio_in_fast(6) }, /* SGPIO8/SGPIO_CLK/P60: SI5351C.CLK2(O) */
|
||||
[PF_4] = { 15, 4, { .mode=7, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_SCK: Unused */
|
||||
[CLK0] = { 24, 0, { .mode=4, .pd=1, .pu=0, .fast=0, .input=1, .ifilt=0 } }, /* SD_CLK: PortaPack SD.CLK, enable input buffer for timing feedback? */
|
||||
|
@@ -69,6 +69,12 @@ void IO::audio_reset_state(const bool active) {
|
||||
io_write(1, io_reg);
|
||||
}
|
||||
|
||||
void IO::reference_oscillator(const bool enable) {
|
||||
const uint8_t mask = 1 << 6;
|
||||
io_reg = (io_reg & ~mask) | (enable ? mask : 0);
|
||||
io_write(1, io_reg);
|
||||
}
|
||||
|
||||
uint32_t IO::io_update(const TouchPinsConfig write_value) {
|
||||
/* Very touchy code to save context of PortaPack data bus while the
|
||||
* resistive touch pin drive is changed. Order of operations is
|
||||
|
@@ -101,6 +101,7 @@ public:
|
||||
void lcd_backlight(const bool value);
|
||||
void lcd_reset_state(const bool active);
|
||||
void audio_reset_state(const bool active);
|
||||
void reference_oscillator(const bool enable);
|
||||
|
||||
void lcd_data_write_command_and_data(
|
||||
const uint_fast8_t command,
|
||||
|
@@ -114,19 +114,14 @@ struct region_t {
|
||||
}
|
||||
};
|
||||
|
||||
constexpr region_t bootstrap {
|
||||
.offset = 0x00000,
|
||||
.size = 0x10000,
|
||||
};
|
||||
|
||||
constexpr region_t images {
|
||||
.offset = 0x10000,
|
||||
.size = 0x70000,
|
||||
.offset = 0x80000,
|
||||
.size = 0x80000,
|
||||
};
|
||||
|
||||
constexpr region_t application {
|
||||
.offset = 0x80000,
|
||||
.size = 0x50000,
|
||||
.offset = 0x00000,
|
||||
.size = 0x80000,
|
||||
};
|
||||
|
||||
} /* namespace spi_flash */
|
||||
|
Binary file not shown.
@@ -26,7 +26,7 @@ import sys
|
||||
usage_message = """
|
||||
PortaPack SPI flash image generator
|
||||
|
||||
Usage: <command> <bootstrap_path> <baseband_path> <application_path> <output_path>
|
||||
Usage: <command> <application_path> <baseband_path> <output_path>
|
||||
Where paths refer to the .bin files for each component project.
|
||||
"""
|
||||
|
||||
@@ -41,33 +41,27 @@ def write_image(data, path):
|
||||
f.write(data)
|
||||
f.close()
|
||||
|
||||
if len(sys.argv) != 5:
|
||||
if len(sys.argv) != 4:
|
||||
print(usage_message)
|
||||
sys.exit(-1)
|
||||
|
||||
bootstrap_image = read_image(sys.argv[1])
|
||||
application_image = read_image(sys.argv[1])
|
||||
baseband_image = read_image(sys.argv[2])
|
||||
application_image = read_image(sys.argv[3])
|
||||
output_path = sys.argv[4]
|
||||
output_path = sys.argv[3]
|
||||
|
||||
spi_size = 1048576
|
||||
|
||||
images = (
|
||||
{
|
||||
'name': 'bootstrap',
|
||||
'data': bootstrap_image,
|
||||
'size': 0x10000,
|
||||
'name': 'application',
|
||||
'data': application_image,
|
||||
'size': 0x80000, #len(application_image),
|
||||
},
|
||||
{
|
||||
'name': 'baseband',
|
||||
'data': baseband_image,
|
||||
'size': 0x70000,
|
||||
'size': 0x80000,
|
||||
},
|
||||
{
|
||||
'name': 'application',
|
||||
'data': application_image,
|
||||
'size': len(application_image),
|
||||
}
|
||||
)
|
||||
|
||||
spi_image = bytearray()
|
||||
|
Reference in New Issue
Block a user